JDK代理要求被代理的类必须实现接口,有很强的局限性。而CGLIB动态代理则没有此类强制性要求。简单的说,CGLIB会让生成的代理类继承被代理类,并在代理类中对代理方法进行强化处理(前置处理、后置处理等)。在CGLIB底层,其实是借助了ASM这个非常强大的Java字节码生成框架。
使用CGLib实现动态代理,完全不受代理类必须实现接口的限制,而且CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。
两者都动态生成了Proxy的java 类的字节码。
代理(Proxy) 从技术上来说可以分为静态代理和动态代理。 从业务上来说主要有两个业务对象,被代理的对象(Target Object)和代理本身(Proxy Object). 分别有两个Class文件. (Target Class) 和(Proxy Class). 静态代理中的Proxy Class就是预先写好的。而动态代理中的Proxy Class是动态生成的字节码。
静态代理的例子
public interface InterfaceA { public void behavior(); } public class AImpl implements InterfaceA { @Override public void behavior() { System.out.println("This is AImpl's behavior method."); } } public class AImpStaticProxy implements InterfaceA{ private AImpl aImpl; public AImpStaticProxy(AImpl aImplObj){ this.aImpl = aImplObj; } @Override public void behavior() { System.out.println("Before calling the Target Object's method"); this.aImpl.behavior(); System.out.println("After calling the Target Object's method"); } }
这里这个静态代理就代理了AImpl这个对象的behavior.
下面是动态代理
public class DynamicProxy implements InvocationHandler { private Object targetObj; public static Object newInstance(Object target){ return java.lang.reflect.Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new DynamicProxy(target)); } private DynamicProxy(Object target){ this.targetObj = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result; try { System.out.println("In Dynamic Proxy: before method " + method.getName()); result = method.invoke(this.targetObj, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } catch (Exception e) { throw new RuntimeException("unexpected invocation exception: " + e.getMessage()); } finally { System.out.println("In Dynamic Proxy: after method " + method.getName()); } return result; } }
用这个代理测试
public interface InterfaceB { public void behavior(); } public class BImpl implements InterfaceB { @Override public void behavior() { System.out.println("This is BImpl"); } } public class Main { public static void testDynamicPorxy(){ AImpl a = new AImpl(); InterfaceA aStaticProxy = new AImpStaticProxy(a); aStaticProxy.behavior(); InterfaceA aDynamicProxy = (InterfaceA) DynamicProxy.newInstance(a); aDynamicProxy.behavior(); InterfaceB b = new BImpl(); InterfaceB bDynamicProxy = (InterfaceB) DynamicProxy.newInstance(b); bDynamicProxy.behavior(); } public static void main(String[] args) throws Exception{ testDynamicPorxy(); } } 输出: Before calling the Target Object's method This is AImpl's behavior method. After calling the Target Object's method In Dynamic Proxy: before method behavior This is AImpl's behavior method. In Dynamic Proxy: after method behavior In Dynamic Proxy: before method behavior This is BImpl In Dynamic Proxy: after method behavior
上面这段例子中,动态生成了两个Proxy class。一个根据InterfaceA以及AImpl生成,一个根据InterfaceB及BImpl生成。这个动态生成的过程由下面的代码实现
java.lang.reflect.Proxy.newProxyInstance()
而最大可以生成65535个动态代理,如底层实现代码如下:
/** * 生成一个代理类,但是在调用本方法之前必须进行权限检查 */ private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) { //如果接口数量大于65535,抛出非法参数错误 if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } // 如果在缓存中有对应的代理类,那么直接返回 // 否则代理类将有 ProxyClassFactory 来创建 return proxyClassCache.get(loader, interfaces); }
Java的动态代理是基于接口的,所以可以CAST到接口上去,但是不能CAST到实现类上去,因为根本不是该实现类。
InterfaceA aDynamicProxy = (InterfaceA) DynamicProxy.newInstance(a); aDynamicProxy.behavior(); InterfaceB b = new BImpl(); InterfaceB bDynamicProxy = (InterfaceB) DynamicProxy.newInstance(b); bDynamicProxy.behavior();
动态生成的代理类名格式大体如下:$Proxy0, $Proxy1......
在我们这个例子中生成的代理类都有一个InvocationHandler成员变量,我们的例子中这个InvocationHandler就是我们定义的DynamicProxy.
换种写法,只实现InvocationHandler, 然后使用Proxy.newInstance来生成代理类和实例。
public class MyInvocationHandler implements InvocationHandler { private Object targetObj; public MyInvocationHandler(Object targetObj) { this.targetObj = targetObj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result; try { beforeCall(proxy,method,args); result = method.invoke(this.targetObj, args); } catch (InvocationTargetException e) { beforeException(proxy,method,args,e); throw e.getTargetException(); } catch (Exception e) { beforeException(proxy,method,args,e); throw new RuntimeException("unexpected invocation exception: " + e.getMessage()); } finally { afterCall(proxy,method,args); } return result; } public void beforeCall(Object proxy, Method method, Object[] args) { System.out.println("In MyInvokeHandler Proxy: before method " + method.getName()); } public void afterCall(Object proxy, Method method, Object[] args) { System.out.println("In MyInvokeHandler Proxy: " + method.getName()); } public void beforeException(Object proxy, Method method, Object[] args,Exception e){ System.out.println("In MyInvokeHandler Proxy:" + e.getMessage()); } } public class Main { public static void testDynamicPorxy(){ AImpl a = new AImpl(); InterfaceA aStaticProxy = new AImpStaticProxy(a); aStaticProxy.behavior(); InterfaceA aDynamicProxy = (InterfaceA) DynamicProxy.newInstance(a); aDynamicProxy.behavior(); InterfaceB b = new BImpl(); InterfaceB bDynamicProxy = (InterfaceB) DynamicProxy.newInstance(b); bDynamicProxy.behavior(); System.out.println("===========InvocationHandler==========="); InterfaceA a1Proxy = (InterfaceA)Proxy.newProxyInstance(a.getClass().getClassLoader(),a.getClass().getInterfaces(),new MyInvocationHandler(a)); a1Proxy.behavior(); } public static void main(String[] args) throws Exception{ testDynamicPorxy(); } }
参考文档:
https://docs.oracle.com/javase/8/docs/technotes/guides/reflection/proxy.html
https://github.com/cglib/cglib
https://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html