前言一、示例代码二、DynamicAdvisedInterceptor三、ReflectiveMethodInvocation
前言
前面简单的写了下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---");
}
}
多配置几个通知类型来观察一下这些通知之间是怎么协调调用的。
二、DynamicAdvisedInterceptorCGLIB的动态代理主要是依靠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
可以看到获取到的任务调用链就是我们写的那几个通知方法
在执行过程中我们定位到了执行代理方法的是这一行。
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 MapuserAttributes; //这个是调用链 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
看一下该类的执行方法,很简单的操作
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里面的打印,打个断点,然后看断点下面的方法调用链就可以找到源码中正在执行的方法了。



