基础
并发编程
框架
动态代理
gdk
利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制生成一个实现代理接口的匿名类,
在调用具体方法前调用InvokeHandler来处理。
JDK动态代理主要涉及两个类:java.lang.reflect.Proxy 和 java.lang.reflect.InvocationHandler
示例:
1 | import java.lang.reflect.InvocationHandler; |
输出:
public abstract void Hello.morning(java.lang.String)
Good morning, Bob
流程:
- 定义一个InvocationHandler实例,它负责实现接口的方法调用;
- 通过Proxy.newProxyInstance()创建interface实例,它需要3个参数:
- 使用的ClassLoader,通常就是接口类的ClassLoader;
- 需要实现的接口数组,至少需要传入一个接口进去;
- 用来处理接口方法调用的InvocationHandler实例。
- 将返回的Object强制转型为接口。
cglib
利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
何时使用JDK还是CGLIB?
- 如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP。
- 如果目标对象实现了接口,可以强制使用CGLIB实现AOP。
- 如果目标对象没有实现了接口,必须采用CGLIB库,Spring会自动在JDK动态代理和CGLIB之间转换。
JDK动态代理和CGLIB字节码生成的区别?
- JDK动态代理只能对实现了接口的类生成代理,而不能针对类。
- CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,
并覆盖其中方法实现增强,但是因为采用的是继承,所以该类或方法最好不要声明成final,
对于final类或方法,是无法继承的。
Spring如何选择用JDK还是CGLIB?
- 当Bean实现接口时,Spring就会用JDK的动态代理。
- 当Bean没有实现接口时,Spring使用CGlib是实现。
- 可以强制使用CGlib(在spring配置中加入
<aop:aspectj-autoproxy proxy-target-/>)。