JDK 代理和 CGLib 有什么区别?
JDK 代理和 CGLib 有什么区别?
动态代理是一种机制,程序通过该机制在运行时动态生成代理对象并调用代理方法。动态代理主要有两种实现机制,一种是基于反射动态代理的JDK,另一种是基于ASM动态代理机制的CGLib实现。现在让我们谈谈两种实现之间的区别以及如何实现它们
JDK 代理和 CGLib 之间的区别
-
JDK动态代理采用反射机制实现,而CGLib基于ASM机制实现,性能不同
-
JDK动态代理是Java语言的内置功能,它不断更新和升级,没有任何维护问题。CGLib是基于第三方工具实现的,两种实现方式往往不同。
-
JDK动态代理必须通过接口实现,调用起来相对简单,而CGLib不需要接口,调用起来相对复杂。
JDKProxy 动态代理实现
JDK 动态代理通过反射类代理和 InvocationHandler 接口实现。由于JDK中的所有动态代理类都必须实现一个接口,也就是说,动态代理类必须实现在动态代理接口中定义的方法,这会导致反射效率低。
- 代码实现
public class JdkTokProxyT implements InvocationHandler { private T target; public JdkTikTokProxy(T target) { this.target = target; } public static T T getProxy(T t) { Object o = Proxy.newProxyInstance(t.getClass().getClassLoader() , t.getClass().getInterfaces() , new JdkTikTokProxy(t)); return (T) o; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // reflection executes System.out.println("Methods that actually execute the proxied object"); Object invoke = method.invoke(target, args); System.out.println("Return value:" + invoke); return null; }}Copy the code
从上面的代码中可以看出,JDK 动态代理使用 Proxy 类中的 newProxyInstance 方法创建一个动态代理对象。
newProxyInstance 方法主要采用
参数 | 描述 |
---|---|
类加载器加载器 | 当前用于装入代理对象的字节码的类装入器。使用与代理对象相同的类装入器。固定写入 |
类?[] 接口 | 当前由可执行对象实现的所有接口的字节码数组,用于使可执行对象和可执行对象具有相同的方法。固定写入 |
InvocationHandler h | 目前,当代理对象执行目标方法时,我们可以使用 H 定义拦截增强方法,即我们编写如何代理。我们通常为此接口编写一个实现类,通常是匿名内部类,但这不是必需的。 |
invoke 方法的主要功能是通过执行支撑对象的任何接口方法传递,或者更确切地说,一个侦听方法,即调用 main 方法参数
参数 | 描述 |
---|---|
代理 | 对代理对象的引用 |
方法 | 当前执行的方法 |
参数 | 当前执行方法所需的参数 |
返回 | 具有与代理对象相同的返回值 |
invoke() 方法是 JDK 代理的调用接口,它使用 Invocation Invo Invocation。
public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
这是因为在动态代理中有一个重要作用,即代理,它用于集中管理prostedobject。显然,InvoHandler 就是这个代理,invoke() 方法是触发代理的执行方法。我们通过实现调用接口来获得动态代理功能。
实施附加
如果使用由 CGLib 实现的动态代理,则不需要代理类来实现接口,这提高了性能,因为 CGLib 使用下面的 ASM 框架,该框架通过字节码技术生成代理类。
动态生成一个支持子类,该子类覆盖支持类的所有非最终方法。方法拦截拦截子类中对父方法的所有调用,将横切逻辑编织到子类中,这比Java的反射JDK动态代理更快.
Cglib 是一个功能强大、高性能的代码生成包,在许多 AOP 框架中广泛用于提供方法拦截
- 代码实现如下
public class CglibProxy { public static T T createProxy(T t) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(t.getClass()); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("Cglib is on."); Object invoke = proxy.invokeSuper(obj, args); returninvoke; }}); Object o = enhancer.create();return(T) o; }}Copy the code
从上面的代码中可以看出,CGLib 是基于子类实现的动态代理,并使用增强器类中的 create 方法创建代理对象。因此,代理类不能由关键字 final 修改。如果由 final 修改,则在使用增强器设置父类时将报告错误,并且无法构建动态代理。