代理 静态代理
主要目的是扩展原有类的功能
例子: 1 2 3 4 public interface Handler { void handle (String data) ; }
1 2 3 4 5 6 7 public class HandlerImpl implements Handler { @Override public void handle (String data) { System.out.println("handle: " + data); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class HandlerProxy implements Handler { private Handler mHandler; public HandlerProxy (Handler handler) { mHandler = handler; } @Override public void handle (String data) { System.out.println("start handle" ); mHandler.handle(data); System.out.println("end handle" ); } } new HandlerProxy(new HandlerImpl()).handle("待处理数据" );
就这样,知道缺点是被代理的类扩展了代理类也需一并扩展。
动态代理 例子: 1 2 3 4 public interface Handler { void handle (String data) ; }
1 2 3 4 5 6 7 public class HandlerImpl implements Handler { @Override public void handle (String data) { System.out.println("handle: " + data); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class MyHandler implements InvocationHandler { private Handler mHandler; public MyHandler (Handler handler) { mHandler = handler; } @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { System.out.println("start handle" ); Object invoke = method.invoke(mHandler, args); System.out.println("end handle" ); return invoke; } }
1 2 3 4 5 6 7 8 9 Handler o = (Handler) Proxy.newProxyInstance( HandlerImpl.class.getClassLoader(), new Class[]{Handler.class}, new MyHandler(new HandlerImpl())); o.handle("待处理数据" );
可以看到,动态代理跟静态代理一样,在代理类内部保存了一个委托类的实例,实际上都是调用原来的委托实例来进行需要的操作。
区别:
动态代理跟静态代理最大的不同便是生成代理类的时期不同,静态代理是在编译期,而动态代理则是在运行时根据委托类信息动态生成
动态代理实现的是InvocationHandler
接口,而静态代理则是直接实现公共接口
动态代理可以获得更多的运行时信息,使用起来也会更加灵活
缺点: 由于最终调用实际逻辑采用方法反射调用的方式,效率并不是很高
原理: 最终通过ProxyGenerator.generateProxyClass()
函数动态生成代理字节码二进制数据,然后通过native方法defineClass0
将字节码加载进方法区,并获取参数为InvocationHandler
的构造器,然后通过该构造器生成实例并传入我们自定义的处理器
注:android中直接通过generateProxy
生成了代理类,并没有走ProxyGenerator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 participant Proxy participant Proxy#ProxyClassFactory participant WeakCache participant WeakCache#Factory Note left of WeakCache:Proxy类里有静态实例WeakCache成员变量\n生成该实例时传入ProxyClassFactory实例 Proxy -> WeakCache:Proxy.getProxyClass0() Note right of WeakCache:优先查找缓存 WeakCache -> WeakCache:proxyClassCache.get() WeakCache -> Proxy:有缓存 Note right of WeakCache:构建Factory工厂类 WeakCache -> WeakCache:new Factory() WeakCache -> WeakCache#Factory:supplier.get() WeakCache#Factory -> Proxy#ProxyClassFactory:valueFactory.apply() Note right of Proxy#ProxyClassFactory:1.类加载器是否解析出相同的class对象 Note right of Proxy#ProxyClassFactory:2.class是否是一个接口 Note right of Proxy#ProxyClassFactory:3.数组类是否重复等判断 Note right of Proxy#ProxyClassFactory:调用defineClass0(native方法)动态生成字节码 Proxy#ProxyClassFactory -> Proxy:ProxyGenerator.generateProxyClass() \n defineClass0() Note right of Proxy:取参数为InvocationHandler构造器 Note right of Proxy:通过构造器生成实例时传入处理器
Cglib动态代理
CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充
通常可以使用Java的动态代理创建代理,但当要代理的类没有实现接口或者为了更好的性能,CGLIB是一个好的选择
git地址:https://github.com/cglib/cglib
cglib-nodep-xxx.jar:使用nodep包不需要关联asm的jar包,jar包内部包含asm的类. cglib-xxx.jar:使用此jar包需要关联asm的jar包,否则运行时报错.
例子: 1 2 3 4 5 6 public class Handler { public void method_1 (String data) {System.out.println(data);} public void method_2 (String data) {System.out.println(data);} public void method_3 (String data) {System.out.println(data);} }
代理: 1 2 3 4 5 6 7 8 9 10 11 Handler handler = (Handler) Enhancer.create(Handler.class, new MethodInterceptor() { @Override public Object intercept (Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("start handle" ); Object result = methodProxy.invokeSuper(o, objects); System.out.println("end handle" ); return result; } }); handler.method_1("待处理数据" );
过滤器:
作用:可以针对不同的方法调用不同的逻辑,
注意:虽然可以在MethodInterceptor
的intercept方法进行区分,但使用过滤器可以有效的减少哈希查找,提高效率
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 NoOp instance = NoOp.INSTANCE; FixedValue fixedValue = new FixedValue() { @Override public Object loadObject () throws Exception { System.out.println("锁定调用结果" ); Object result = 1 ; return result; } }; MethodInterceptor methodInterceptor = new MethodInterceptor() { @Override public Object intercept (Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("start handle" ); Object result = methodProxy.invokeSuper(o, objects); System.out.println("end handle" ); return result; } }; Handler handler = (Handler) Enhancer.create(Handler.class, null , new CallbackFilter() { @Override public int accept (Method method) { if (method.getName().equals("method_1" )){ return 2 ; } else if (method.getName().equals("method_2" )) { return 1 ; } return 0 ; } }, new Callback[]{instance, fixedValue, methodInterceptor}); handler.method_1("method_1" ); handler.method_2("method_2" ); handler.method_3("method_3" );
延迟加载: 1 2 3 4 5 6 public class LazyBeam { private String name; public String getName () {return name;} public void setName (String name) {this .name = name;} }
1 2 3 4 5 6 7 8 9 10 11 LazyBeam lazyBeam = (LazyBeam) Enhancer.create(LazyBeam.class, null , new LazyLoader() { @Override public Object loadObject () throws Exception { System.out.println("加载数据" ); LazyBeam lazyBeam = new LazyBeam(); lazyBeam.setName("lazyBeam" ); return lazyBeam; } }); System.out.println(lazyBeam.getName());
1 2 3 4 5 6 7 8 9 10 11 LazyBeam lazyBeam = (LazyBeam) Enhancer.create(LazyBeam.class, null , new Dispatcher() { @Override public Object loadObject () throws Exception { System.out.println("加载数据" ); LazyBeam lazyBeam = new LazyBeam(); lazyBeam.setName("lazyBeam" ); return lazyBeam; } }); System.out.println(lazyBeam.getName());
接口生成: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 InterfaceMaker maker = new InterfaceMaker(); maker.add(Handler.class); Class<?> aClass = maker.create(); for (Method method : aClass.getMethods()) { System.out.println(method.getName()); } Object obj = Enhancer.create(Object.class, new Class[]{aClass}, new MethodInterceptor() { @Override public Object intercept (Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { if (method.getName().equals("method_1" )) { System.out.println("执行方法1" ); return "方法1" ; } if (method.getName().equals("method_2" )) { System.out.println("执行方法2" ); return "方法2" ; } return null ; } }); Method method_1 = aClass.getMethod("method_1" , String.class); method_1.invoke(obj,"方法1" ); Method method_2 = aClass.getMethod("method_2" , String.class); method_2.invoke(obj,"方法2" );
原理: 表层原理: 动态生成代理类的子类,子类重写要代理的类的所有不是final/private的方法。在子类采用方法拦截的技术拦截所有父类方法的调用。
底层原理: 使用字节码处理框架ASM,来转换字节码并生成新的类。注:不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
优点: 相较与JDK动态代理
可以实现接口和类的代理,局限性更小【注:代理接口调用invokeSuper
相当于直接调用未实现的接口方法,会直接报错 】
由于与实际编写继承代码无异,采用的是动态用生成子类方式,方法执行效率要高
有丰富的操作策略以适应不同的业务
缺点: 由于采用继承的关系,对私有方法和final方法无法代理
包说明: net.sf.cglib.core
:底层字节码处理类,他们大部分与ASM有关系。net.sf.cglib.transform
:编译期或运行期类和类文件的转换net.sf.cglib.proxy
:实现创建代理和方法拦截器的类net.sf.cglib.reflect
:实现快速反射和C#风格代理的类net.sf.cglib.util
:集合排序等工具类net.sf.cglib.beans
:JavaBean相关的工具类