Java 记录实例的任何方法调用

Java 记录实例的任何方法调用,java,reflection,proxy,interceptor,Java,Reflection,Proxy,Interceptor,是否可以记录类实例的任何方法调用?我有以下的例子: InputStream serverInputStream = this.serverProcess.getInputStream(); 我想看看在运行时的某个给定时间,在serverInputStream中调用了什么方法。我认为解决这个问题的办法是反射,特别是代理。我已经试过让它工作,但无法让它运行 我想到了一个类似的代码: MyInterceptor myInterceptor = new MyInterceptor(this.serve

是否可以记录类实例的任何方法调用?我有以下的例子:

InputStream serverInputStream = this.serverProcess.getInputStream();
我想看看在运行时的某个给定时间,在
serverInputStream
中调用了什么方法。我认为解决这个问题的办法是反射,特别是代理。我已经试过让它工作,但无法让它运行

我想到了一个类似的代码:

MyInterceptor myInterceptor = new MyInterceptor(this.serverProcess.getInputStream());
InputStream serverInputStream = myInterceptor.getInterceptedInstance();

serverInputStream.methodOne();
serverInputStream.methodTwo();
serverInputStream.methodThree();

myInterceptor.printIntercepts();
1. InputStream.InputStream();
2. InputStream.methodOne();
3. InputStream.methodTwo();
4. InputStream.methodThree();
具有与此类似的结果:

MyInterceptor myInterceptor = new MyInterceptor(this.serverProcess.getInputStream());
InputStream serverInputStream = myInterceptor.getInterceptedInstance();

serverInputStream.methodOne();
serverInputStream.methodTwo();
serverInputStream.methodThree();

myInterceptor.printIntercepts();
1. InputStream.InputStream();
2. InputStream.methodOne();
3. InputStream.methodTwo();
4. InputStream.methodThree();

这可能吗?

这里有两个选项:

  • 使用JDK中包含的动态代理功能,或
  • 使用字节码操纵库,如ASM

  • java.lang.reflect.Proxy只能生成一组接口的实现,而字节码操作库也可以修补现有类。

    这里有两个选项:

  • 使用JDK中包含的动态代理功能,或
  • 使用字节码操纵库,如ASM

  • java.lang.reflect.Proxy只能生成一组接口的实现,而字节码操作库也可以修补现有的类。

    为什么不能只编写一个?然后,您只需将要观看的
    InputStream
    包装为其中一个

    class LoggingInputStream extends InputStream {
        private final InputStream original;
    
        public LoggingInputStream(InputStream original) {
            super();
            this.original = original;
        }
    
        @Override
        public int read(byte[] b) throws IOException {
            // Logging here - and below.
            return super.read(b);
        }
    
        @Override
        public int read(byte[] b, int off, int len) throws IOException {
            return super.read(b, off, len);
        }
    
        @Override
        public long skip(long n) throws IOException {
            return super.skip(n);
        }
    
        @Override
        public int available() throws IOException {
            return super.available();
        }
    
        @Override
        public void close() throws IOException {
            super.close();
        }
    
        @Override
        public synchronized void mark(int readlimit) {
            super.mark(readlimit);
        }
    
        @Override
        public synchronized void reset() throws IOException {
            super.reset();
        }
    
        @Override
        public boolean markSupported() {
            return super.markSupported();
        }
    
        @Override
        public int read() throws IOException {
            return original.read();
        }
    }
    

    这是IntelliJ自动生成的。

    有什么原因不能只写一个吗?然后,您只需将要观看的
    InputStream
    包装为其中一个

    class LoggingInputStream extends InputStream {
        private final InputStream original;
    
        public LoggingInputStream(InputStream original) {
            super();
            this.original = original;
        }
    
        @Override
        public int read(byte[] b) throws IOException {
            // Logging here - and below.
            return super.read(b);
        }
    
        @Override
        public int read(byte[] b, int off, int len) throws IOException {
            return super.read(b, off, len);
        }
    
        @Override
        public long skip(long n) throws IOException {
            return super.skip(n);
        }
    
        @Override
        public int available() throws IOException {
            return super.available();
        }
    
        @Override
        public void close() throws IOException {
            super.close();
        }
    
        @Override
        public synchronized void mark(int readlimit) {
            super.mark(readlimit);
        }
    
        @Override
        public synchronized void reset() throws IOException {
            super.reset();
        }
    
        @Override
        public boolean markSupported() {
            return super.markSupported();
        }
    
        @Override
        public int read() throws IOException {
            return original.read();
        }
    }
    

    这是IntelliJ自动生成的。

    我想尝试一下Java方面。通过定义一些切入点,您可以监视或劫持其他类方法的行为,截取参数,计算方法被调用的次数

    让我们举个例子:

    package org.bpa.fd;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    
    @Aspect
    public class ListAspect {
    
        @Pointcut("call(public * java.io.InputStream.*(..))")
        public void inputStreamMethod() {
        }
    
        @Before("inputStreamMethod()")
        public void anyMethod(JoinPoint jp) {
            System.out.println(jp.toLongString());
        }
    }
    
    通过这个切入点,您将看到对InputStream类的公共方法的任何调用。JointPoint还存储方法参数,以获得更完整的概述

    您可以使用gradle导入此库:

    buildscript {
        repositories {
            maven {
                url "https://maven.eveoh.nl/content/repositories/releases"
            }
        }
    
        dependencies {
            classpath "nl.eveoh:gradle-aspectj:2.0"
        }
    }
    
    project.ext {
        aspectjVersion = '1.8.12'
    }
    
    apply plugin: 'aspectj'
    

    摘自:

    我想尝试一下Java方面。通过定义一些切入点,您可以监视或劫持其他类方法的行为,截取参数,计算方法被调用的次数

    让我们举个例子:

    package org.bpa.fd;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    
    @Aspect
    public class ListAspect {
    
        @Pointcut("call(public * java.io.InputStream.*(..))")
        public void inputStreamMethod() {
        }
    
        @Before("inputStreamMethod()")
        public void anyMethod(JoinPoint jp) {
            System.out.println(jp.toLongString());
        }
    }
    
    通过这个切入点,您将看到对InputStream类的公共方法的任何调用。JointPoint还存储方法参数,以获得更完整的概述

    您可以使用gradle导入此库:

    buildscript {
        repositories {
            maven {
                url "https://maven.eveoh.nl/content/repositories/releases"
            }
        }
    
        dependencies {
            classpath "nl.eveoh:gradle-aspectj:2.0"
        }
    }
    
    project.ext {
        aspectjVersion = '1.8.12'
    }
    
    apply plugin: 'aspectj'
    
    摘自:

    如果您想做一些类似Java动态代理的事情,那么它可能是一种替代解决方案。它真的很轻,使用方便

    Maven配置:

    <dependency>
        <groupId>com.ericsson.commonlibrary</groupId>
        <artifactId>proxy</artifactId>
        <version>1.2.0</version>
    </dependency>
    
    
    com.ericsson.commonlibrary
    代理
    1.2.0
    
    满足您的请求的代码示例:

    public class ProxyExample { public static void main(String[] args) { SomeImpl proxy = Proxy.intercept(new SomeImpl(), new MyInterceptor()); proxy.log("hello world"); //Output: //SomeImpl.log //hello world } public static class SomeImpl { public void log(String log) { System.out.println(log); } } public static class MyInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { System.out.println(invocation.getThis().getClass().getSuperclass().getSimpleName() + "." + invocation.getMethodName()); Object returnObject = invocation.invoke(); //original method invocation. return returnObject; } } } 公共类代理示例{ 公共静态void main(字符串[]args){ SomeImpl proxy=proxy.intercept(new SomeImpl(),new MyInterceptor()); log(“你好世界”); //输出: //SomeImpl.log //你好,世界 } 公共静态类SomeImpl{ 公共无效日志(字符串日志){ 系统输出打印项次(日志); } } 公共静态类MyInterceptor实现拦截器{ @凌驾 公共对象拦截(调用)抛出可丢弃的{ System.out.println(invocation.getThis().getClass().getSuperclass().getSimpleName()+“+”+invocation.getMethodName()); Object returnObject=invocation.invoke();//原始方法调用。 返回对象; } } } 如果您想做一些类似Java动态代理的事情,这可能是一种替代解决方案。它真的很轻,使用方便

    Maven配置:

    <dependency>
        <groupId>com.ericsson.commonlibrary</groupId>
        <artifactId>proxy</artifactId>
        <version>1.2.0</version>
    </dependency>
    
    
    com.ericsson.commonlibrary
    代理
    1.2.0
    
    满足您的请求的代码示例:

    public class ProxyExample { public static void main(String[] args) { SomeImpl proxy = Proxy.intercept(new SomeImpl(), new MyInterceptor()); proxy.log("hello world"); //Output: //SomeImpl.log //hello world } public static class SomeImpl { public void log(String log) { System.out.println(log); } } public static class MyInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { System.out.println(invocation.getThis().getClass().getSuperclass().getSimpleName() + "." + invocation.getMethodName()); Object returnObject = invocation.invoke(); //original method invocation. return returnObject; } } } 公共类代理示例{ 公共静态void main(字符串[]args){ SomeImpl proxy=proxy.intercept(new SomeImpl(),new MyInterceptor()); log(“你好世界”); //输出: //SomeImpl.log //你好,世界 } 公共静态类SomeImpl{ 公共无效日志(字符串日志){ 系统输出打印项次(日志); } } 公共静态类MyInterceptor实现拦截器{ @凌驾 公共对象拦截(调用)抛出可丢弃的{ System.out.println(invocation.getThis().getClass().getSuperclass().getSimpleName()+“+”+invocation.getMethodName()); Object returnObject=invocation.invoke();//原始方法调用。 返回对象; } } }
    为了扩大宁使用代理的建议, 您可以简单地使用oneliner:

    InputStream serverInputStream = Proxy.addTimerToMethods(this.serverProcess.getInputStream());
    serverInputStream.anymethodreally();
    // any usage will now be printed to console with parameters+ performance data
    
    使用新的Java 8+API对Ning的代理建议进行了更清晰的重写:

         InputStream serverInputStream = with(this.serverProcess.getInputStream())
                    .interceptAll(i -> {
                        Object result = i.invoke();
                        System.out.println("after method: " + i.getMethodName() + " param: " + i.getParameter0());
                        return result;
                    }).get();
         serverInputStream.anymethodreally();
        // any usage will now be printed to console(or whatever you decide to do!)
    
    使用代理而不是AspectJ的绝对主要好处是不需要学习一些自定义编译或语言。 代理基本上是一个更轻量级、更易于使用的解决方案(当然,它也有局限性)

    和普通的decorator/interceptor/proxy类相比,使用代理当然不需要创建一个实现每个方法的新类。您也不必为每一个额外的类实现一个新的decorator/interceptor/proxy类


    Proxy基本上允许您创建一个可以应用于任何类的通用方法拦截器。

    为了扩展Ning使用Proxy的建议, 您可以简单地使用oneliner:

    InputStream serverInputStream = Proxy.addTimerToMethods(this.serverProcess.getInputStream());
    serverInputStream.anymethodreally();
    // any usage will now be printed to console with parameters+ performance data
    
    使用新的Java 8+API对Ning的代理建议进行了更清晰的重写:

         InputStream serverInputStream = with(this.serverProcess.getInputStream())
                    .interceptAll(i -> {
                        Object result = i.invoke();
                        System.out.println("after method: " + i.getMethodName() + " param: " + i.getParameter0());
                        return result;
                    }).get();
         serverInputStream.anymethodreally();
        // any usage will now be printed to console(or whatever you decide to do!)
    
    使用代理而不是AspectJ的绝对主要好处是不需要学习一些自定义编译或语言。 代理基本上是一个更轻量级、更易于使用的解决方案(当然,它也有局限性)

    和普通的decorator/interceptor/proxy类相比,使用proxy当然不需要创建一个