前言
前面简单的写了下Spring AOP中是怎么实现动态代理的,简单的来说是通过bean对象的后置管理器对实例化的bean对象做判断后使用不同的动态代理方式,下面来看一下生成的动态代理是怎么执行的。
一、示例代码
@Aspect
@Component
public class MyAspect {
@Pointcut("execution(public void com.jack.service.TestService.doSomething())")
public void point(){}
@Before("point()")
public void beforeMethod(JoinPoint joinPoint) {
System.out.println("beforeMethod----");
}
@After("point()")
public void afterMethod(JoinPoint joinPoint) {
System.out.println("afterMethod----");
}
@AfterReturning("point()")
public void AfterReturning() {
System.out.println("AfterReturning----");
}
@AfterThrowing("point()")
public void AfterThrowing() {
System.out.println("AfterThrowing----");
}
@Around("point()")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("around start---");
proceedingJoinPoint.proceed();
System.out.println("around end---");
}
}
多配置几个通知类型来观察一下这些通知之间是怎么协调调用的。
二、DynamicAdvisedInterceptor
CGLIB的动态代理主要是依靠MethodInterceptor来实现的,看一下AOP中CglibAopProxy类,在这个类里面有个内部类DynamicAdvisedInterceptor,仔细一看这个类它的父类是MethodInterceptor瞬间就清晰了,这就是最后CGLIB代理的执行类。
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
private final AdvisedSupport advised;
public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
}
@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
//获取代理对象等属性一系列操作
TargetSource targetSource = this.advised.getTargetSource();
try {
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
//获取任务调用链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
//进行了一系列判断,最终断点没走这
if (chain.isEmpty() && CglibMethodInvocation.isMethodProxyCompatible(method)) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
try {
retVal = methodProxy.invoke(target, argsToUse);
}
catch (CodeGenerationException ex) {
CglibMethodInvocation.logFastClassGenerationFailure(method);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
}
else {
//断点走了这里,当走完这一行发现打印完所有语句了,应该是在这里进行的调用
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
...
}
可以看到获取到的任务调用链就是我们写的那几个通知方法
在执行过程中我们定位到了执行代理方法的是这一行。
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
三、ReflectiveMethodInvocation
CglibMethodInvocation的父类是ReflectiveMethodInvocation,这是最终执行的父类。
看一下其属性
//代理类
protected final Object proxy;
protected final Object target;
//被代理的方法切面
protected final Method method;
protected Object[] arguments;
private final Class<?> targetClass;
//这个打断点后发现里面存放的是切点
private Map<String, Object> userAttributes;
//这个是调用链
protected final List<?> interceptorsAndDynamicMethodMatchers;
//调用链坐标
private int currentInterceptorIndex = -1;
可以看到上面的方法CGLIB调用操作最终是对其属性进行赋值。
protected ReflectiveMethodInvocation(
Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,
@Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
this.proxy = proxy;
this.target = target;
this.targetClass = targetClass;
this.method = BridgeMethodResolver.findBridgedMethod(method);
this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
}
看一下该类的执行方法,很简单的操作
public Object proceed() throws Throwable {
// 获取调用链的长度
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
//获取当前该执行的通知任务
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
//任务通知的动态匹配,断点没走这
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
return proceed();
}
}
else {
//最终断点走了else
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
看断点的结果可以得出结论,代理任务中的多种代理方式都有一个对应的实现类,然后按照代理的顺序去调用不同的代理类。
随便看一个MethodBeforeAdviceInterceptor中的实现
public Object invoke(MethodInvocation mi) throws Throwable {
//调用前置处理方法
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
//调用方法
return mi.proceed();
}
其实在Spring中的动态代理最终的执行使用的是责任链设计模式。大家可以自己看一下JDK动态代理的实现方式,最终是一样的。
在这里教大家一个看源码的小技巧,假设我们对CglibMethodInvocation类不了解,不知道它的执行方法是哪个怎么办呢?我们点到了配置方法没有看到运行。
可以这样做,随便找个要执行的方法,例如before里面的打印,打个断点,然后看断点下面的方法调用链就可以找到源码中正在执行的方法了。