JAVA: JDK动态代理

什么是动态代理

动态代理就是,在程序运行期,创建目标对象的代理对象,并对目标对象中的方法进行功能性增强的一种技术。在生成代理对象的过程中,目标对象不变,代理对象中的方法是目标对象方法的增强方法。可以理解为运行期间,对象中方法的动态拦截,在拦截方法的前后执行功能操作。

JDK动态代理

JDK动态代理是一种基于接口的动态代理,代理对象必须是实现接口,通过使用JDK官方的Proxy类创建代理对象。JDK的动态代理主要涉及到java.lang.reflect包的两个类:Proxy和InvocationHandler。其中InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一起。而Proxy是利用InvocationHandler动态创建一个符合某一个接口实例,生成目标类的代理对象

对象说明

每一个动态代理类的调用处理程序都必须实现InvocationHandler接口,并且每个代理类的实例都关联到了实现该接口的动态代理类调用处理程序中,当我们通过动态代理对象调用一个方法时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用,并在invoke方法中实现增强,看如下invoke方法:

public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
    throws Throwable;

}

proxy:代理类代理的真实代理对象com.sun.proxy.$Proxy0

method:我们所要调用某个对象真实的方法的Method对象

args:指代代理对象方法传递的参数

Proxy类就是用来创建一个代理对象的类,它提供了很多方法,但是我们最常用的是newProxyInstance方法。这个方法的作用就是创建一个代理类对象,它接收三个参数

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h) {
  // ......
}

loader:一个classloader对象,定义了由哪个classloader对象对生成的代理类进行加载

interfaces:一个interface对象数组,表示我们将要给我们的代理对象提供一组什么样的接口,如果我们提供了这样一个接口对象数组,那么也就是声明了代理类实现了这些接口,代理类就可以调用接口中声明的所有方法。

h:一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用。

代码示例

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DynamicProxyTest {

    interface IHello {
        void sayHello(String name);
    }

    static class Hello implements IHello {
        @Override
        public void sayHello(String name) {
            System.out.println("hello, "+name);
        }
    }

    static class DynamicProxy implements InvocationHandler {

        Object originalObj; //真实处理对象

        /**
         * @param originalObj  真实处理对象
         * @return
         */
        Object bind(Object originalObj) {
            this.originalObj = originalObj;
            //通过Proxy类的newProxyInstance方法创建代理对象,返回一个实现了IHello接口的代理对象实例,
            // 调用getProxyClass方法返回代理类的Class对象
            return Proxy.newProxyInstance(originalObj.getClass().getClassLoader(), originalObj.getClass().getInterfaces(), this);
        }


        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //TODO:实现增强例如: 真实对象处理前增加某个操作
            System.out.println("before invoke...");
            Object object= method.invoke(originalObj, args);
            //TODO:实现增强例如: 真是对象处理后增加某个操作
            System.out.println("before invoke...");

            return object;
        }
    }

    public static void main(String[] args) {
        //
        IHello hello = (IHello) new DynamicProxy().bind(new Hello());
        hello.sayHello("zhang san");

    }
}

文章总结

Java标准库提供了动态代理功能,允许在运行期动态创建一个接口的实例

  • JDK动态代理是通过 Proxy动态生成代理类,调用getProxyClass方法返回代理类的Class对象。通过Class.forName(……)方法加载并校验(是不是接口类、是不是同一个加载器加载、有没有重复的接口类)
  • JDK动态代理通过实现InvocationHandler接口invoke方法实现功能增强

上一篇:JVM从虚拟机层面了解重载和重写

上一篇:TensorFlow restore lhs shape rhs shape 的错


下一篇:Spring日常笔记记录10--动态代理实现InvocationHandler