java 动态代理机制
代理模式是Java中常用的设计模式,主要由公共接口、被代理类和代理类等三部分组成,代理类持有被代理类的实类,代理为执行具体的类方法。其中代理类与被代理类有同样的接口。
代理类的对象本身并不真正实现服务,而是通过调用被代理类对象的方法来提供特定的服务。
代理分为静态代理和动态代理,编译时能确定被代理的类就是静态, 在运行过程中确定要被代理的类则是动态代理
静态代理:
public class daili_demo { public static void start(a a){ a.echo(); } public static void main(String[] args){ daili_demo.start(new proxy_subject()); } } interface a{ void echo(); } class real_subject implements a{ public void echo(){ System.out.println("real echo"); } public static void test(){ System.out.println("test"); } } class proxy_subject implements a{ public void echo(){ System.out.println("start"); new real_subject().echo(); new real_subject().test(); System.out.println("end"); } }
比如上面这段代码实际上proxy_subject和real_subject有相同的接口,proxy_subject即代理类,我们可以在其中调用被代理类的方法,也可以在代理类中实现自己的逻辑,比如在被代理的real_subject的echo调用之前或调用之后添加自己的逻辑
动态代理:
在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象。在程序运行过程中产生的这个对象,其实就是通过反射机制来生成的一个代理。
每一个动态代理类都必须要实现InvocationHandler这个接口
InvocationHandler:
该接口只有一个方法invoke,动态代理类都必须实现该接口,那么也必须要实现该方法,入口参数Object proxy即为要被代理的对象,method为被调用的方法,args为参数
Proxy类
jdk说明中也说了一种简单的方式用于创建动态代理,通过调用Proxy.newProxyInstance函数,proxy类是支持序列化的
import java.lang.reflect.Proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class dongtaidaili_demo { public static void main(String[] args){ read_object ppp = new read_object(); daili handler = new daili(ppp); b get_b = (b)Proxy.newProxyInstance(ppp.getClass().getClassLoader(),ppp.getClass().getInterfaces(),handler); get_b.fun1(); } } interface b{ public void fun1(); public void fun2(); } class read_object implements b{ public void fun1() { System.out.println("fun1"); } public void fun2() { System.out.println("fun2"); } } class daili implements InvocationHandler{ private Object subject; daili(Object subject){ this.subject = subject; } public Object invoke(Object object, Method method, Object[] args) throws Throwable { System.out.println("start"); System.out.println(method); method.invoke(subject,args); System.out.println("end"); return null; } }
JDK会生成一个叫$Proxy0的代理类,这个类文件是放在内存中的,在创建代理类对象时,通过反射机制获得这个类的构造方法,然后创建代理类实例。
所以整个创建动态代理的流程为首先要声明被代理的接口,然后声明所需要的代理类,然后创建动态代理类,该类要实现invocationhandler接口,然后实现invoke方法,也就是具体的代理处理逻辑,并且要通过该类的构造方法将被代理的对象传进代理类,以便于在invoke函数中进行反射调用。实现代理与被代理的联系是通过newProxyNewinstance,此时要传入classloader,一组接口(就是想要被代理的),以及动态处理类,那么返回的也是一个接口,这个接口可以是一组接口中的任何一个,通过该接口来调用接口内的方法就能够触发动态代理类内部的invoke函数来实现,classloader是sun.misc.Launcher$AppClassLoader,所以最后可以得到jdk中动态代理实际上就是给接口做的代理
为什么说是动态代理也就是程序运行时通过这三句才确定的代理与被代理的关系
参考:
https://www.mi1k7ea.com/2019/02/01/Java%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E6%9C%BA%E5%88%B6/