前言
SpringAOP主要基于动态代理实现,而动态代理有JDK动态代理和CGLIB动态代理,对于实现了接口的spring默认会使用JDK动态代理,而没有实现接口的会使用CGLIB动态代理
- JDK动态代理只能用于实现了接口的类是因为生成的代理类继承了Proxy,而Java为单继承,所以只能通过实现接口的方法
- 而CGLIB可以通过继承被代理类,也可以通过实现接口方法
接下来展示一个迷你版Spring的CGLIB动态代理是如何实现方法增强的,本例展示前置和后置增强
我们直接从测试类开始出发
CGLIB动态代理
ini
@Test
public void testAdvisor() throws Exception {
WorldService worldService = new WorldServiceImpl();
//Advisor是Pointcut和Advice的组合
//这里增强的是explode方法
String expression = "execution(* org.springframework.test.service.WorldService.explode(..))";
//第一个切面
AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
advisor.setExpression(expression);
MethodBeforeAdviceInterceptor methodInterceptor = new MethodBeforeAdviceInterceptor(new WorldServiceBeforeAdvice());
advisor.setAdvice(methodInterceptor);
//第二个切面
AspectJExpressionPointcutAdvisor advisor1 = new AspectJExpressionPointcutAdvisor();
advisor1.setExpression(expression);
AfterReturningAdviceInterceptor afterReturningAdviceInterceptor = new AfterReturningAdviceInterceptor(new WorldServiceAfterReturnAdvice());
advisor1.setAdvice(afterReturningAdviceInterceptor);
//通过ProxyFactory来获得代理
ProxyFactory factory = new ProxyFactory();
TargetSource targetSource = new TargetSource(worldService);
factory.setTargetSource(targetSource);
factory.setProxyTargetClass(true); //ProxyTargetClass(true表示CGLIB动态代理,False表示JDK动态代理)
factory.addAdvisor(advisor);
factory.addAdvisor(advisor1);
WorldService proxy = (WorldService) factory.getProxy();
proxy.explode();
}
- 创建前置增强和后置增强,将其和目标对象放入代理工厂,由代理工厂动态创建代理类,同过getProxy获得Object类型强转为worldService。
scala
public class ProxyFactory extends AdvisedSupport{
public ProxyFactory() {
}
public Object getProxy() {
return createAopProxy().getProxy();
}
private AopProxy createAopProxy() {
if (this.isProxyTargetClass()||this.getTargetSource().getTargetClass().length==0) {
return new CglibAopProxy(this);
}
return new JdkDynamicAopProxy(this);
}
}
- createAopProxy主要判断用Cglib动态代理还是JDK动态代理
-
- this.isProxyTargetClass(),表示是否使用CGLIB动态代理
- this.getTargetSource().getTargetClass().length==0,表示该类没有实现任何接口
- 这里我们选择的是CGLIB
java
public class CglibAopProxy implements AopProxy {
private final AdvisedSupport advised;
public CglibAopProxy(AdvisedSupport advised) {
this.advised = advised;
}
@Override
public Object getProxy() {
// 创建动态代理增强类
Enhancer enhancer = new Enhancer();
// 要代理的对象的class
enhancer.setSuperclass(advised.getTargetSource().getTarget().getClass());
//被代理对象实现的接口(类实现了接口就用这个)
enhancer.setInterfaces(advised.getTargetSource().getTargetClass());
// 设置代理的回调,Callback的实现类
enhancer.setCallback(new DynamicAdvisedInterceptor(advised));
return enhancer.create();
}
- 这里就返回了代理类
- 再回到测试类,方法执行到proxy.explode();
- proxy.explode();执行,此时CGLIB会使用设置的回调对象 DynamicAdvisedInterceptor 来拦截和处理这个方法调用。
ini
//这个类为CglibAopProxy的内部类
private static class DynamicAdvisedInterceptor implements MethodInterceptor {
private final AdvisedSupport advised;
private DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 获取目标对象
Object target=advised.getTargetSource().getTarget();
Class<?> targetClass = target.getClass();
Object retVal = null;
//获取拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
CglibMethodInvocation methodInvocation = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy);
if(chain==null||chain.isEmpty()){
////如果拦截器链为空,就执行目标对象的方法,否则执行拦截器链中的方法
retVal =methodProxy.invoke(target, args);
}else retVal=methodInvocation.proceed();
return retVal;
}
}
- getInterceptorsAndDynamicInterceptionAdvice方法用于获取拦截器链
kotlin
/**
* 用来返回方法的拦截器链,方法属于AdvisedSupport
*/
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
Integer cacheKey=method.hashCode();
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
//获得拦截器链后加入到缓存
this.methodCache.put(cacheKey, cached);
}
return cached;
}
- 通过 method.hashCode() 生成一个缓存的键值 cacheKey,使用 cacheKey 从 methodCache 中获取已经缓存的拦截器列表。
- 如果cached为空,则通过AdvisedSupport的拦截器链工厂的getInterceptorsAndDynamicInterceptionAdvice方法获取拦截器链。
ini
/**
* 拦截器链的默认实现类
**/
public class DefaultAdvisorChainFactory implements AdvisorChainFactory {
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(AdvisedSupport config, Method method, Class<?> targetClass) {
//在测试类已经添加两个advisor
Advisor[] advisors = config.getAdvisors().toArray(new Advisor[0]);
List<Object> interceptorList = new ArrayList<>(advisors.length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
for (Advisor advisor : advisors) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
// 校验当前Advisor是否适用于当前对象
if (pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
// 校验Advisor是否应用到当前方法上
match = mm.matches(method, actualClass);
if (match) {
MethodInterceptor interceptor = (MethodInterceptor) advisor.getAdvice();
interceptorList.add(interceptor);
}
}
}
}
return interceptorList;
}
}
- 拿到拦截器链后回到intercept方法,会判断拦截器链是否为空
- 为空执行目标对象方法,不为空执行拦截器链方法proceed
scala
private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
private final MethodProxy methodProxy;
public CglibMethodInvocation(Object proxy, Object target, Method method,
Object[] arguments, Class<?> targetClass,
List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {
super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
this.methodProxy = methodProxy;
}
@Override
public Object proceed() throws Throwable {
return super.proceed();
}
}
- 会调用父类ReflectiveMethodInvocation的proceed方法,接下来看看该方法
kotlin
public Object proceed() throws Throwable {
// 初始currentInterceptorIndex为-1,每调用一次proceed就把currentInterceptorIndex+1
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 当调用次数 = 拦截器个数时
// 触发当前method方法
return method.invoke(this.target, this.arguments);
}
//拿出一个拦截器就currentInterceptorIndex+1
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 普通拦截器,直接触发拦截器invoke方法,会把当前ReflectiveMethodInvocation作为参数
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
- interceptorsAndDynamicMethodMatchers就是切面链,ReflectiveMethodInvocation的构造函数会把切面链放到成员变量interceptorsAndDynamicMethodMatchers。
- 该方法就是会把拦截器链的拦截器都执行了对应的拦截方法,执行完了就会触发目标对象的那个方法执行。
- 而invoke执行的就是BeforeAdvice和AfterAdvice的invoke,测试类加的是这两个,举例一个看看
java
public class MethodBeforeAdviceInterceptor implements MethodInterceptor , BeforeAdvice {
private MethodBeforeAdvice advice;
public MethodBeforeAdviceInterceptor() {
}
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
this.advice = advice;
}
public void setAdvice(MethodBeforeAdvice advice) {
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
//在执行被代理方法之前,先执行before advice操作
this.advice.before(invocation.getMethod(), invocation.getArguments(), invocation.getThis());
//执行完后进行返回前面的proceed方法进行判断
return invocation.proceed();
}
}
- 当执行完拦截器方法后就会执行目标对象方法,然后就进行返回了,这样一个带有前置和后置增强的代理类执行目标对象方法就完成了。
拓展
cglib和jdk动态代理使用场景
- 目标对象生成了接口 默认用JDK动态代理
- 如果目标对象使用了接口,也可以强制使用CGLIB
- 如果目标对象没有实现接口,必须采用CGLIB动态代理,Spring会自动在JDK动态代理和CGLIB之间转换
CGLIB与JDK效率对比
- CGLIB底层是ASM字节码生成框架,但是字节码技术生成代理类,在JDK1.6之前比使用Java反射的效率要高
- 在Jdk6之后逐步对JDK动态代理进行了优化,在调用次数比较少时效率高于CGLIB代理效率,但是在大量调用的时候CGLIB的效率高
- 在JDK1.8的时候JDK动态代理的效率已高于CGLIB
注意事项
- CGLIB不能对声明final的方法进行代理,因为CGLIB是动态生成代理对象,final关键字修饰的类不可变只能被引用不能被修改
区别 | CGLIB | JDK动态代理 |
---|---|---|
原理 | 动态生成一个要代理的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截技术拦截所有的父类方法的调用,顺势织入横切逻辑,它比Java反射的jdk动态代理要快 | JDK中的动态代理是通过反射类Proxy以及InvocationHandler回调接口实现的,但是JDK中所有要进行动态代理的类必须要实现一个接口,也就是说只能对该类所实现接口中定义的方法进行代理,这在实际编程中有一定的局限性,而且使用反射的效率较慢 |
是否提供子类代理 | 是 | 否 |
是否提供接口代理 | 是(可不用接口) | 是(必须) |