概述
上篇文章中详细介绍了 SpringAOP 的前期准备过程,即:代理的创建。包括和AOP相关后置处理器的创建及待增强Bean的创建。本篇文章将在上篇文章的基础上,介绍SpringAOP的代理执行过程。
之前的配置类AopConfig、切面类LogAspect以及需要被Aop增强的类MathService的代码略,可以点击《SpringAOP介绍及基础用法》查看,测试类AopTest如下:
/**
* Aop测试
* @date: 2022/2/28 13:36
*/
public class AopTest {
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(AopConfig.class);
MathService mathService = ac.getBean("mathService", MathService.class);
mathService.division(4, 2);
}
}
整个Aop的执行过程分为拦截器链的创建过程及拦截器链的执行过程,创建过程就是将每个被增强的类中的方法依次包装为一个方法拦截器对象MethodInterceptor,然后放入一个List集合中,组成一个拦截器链;而拦截器链的执行过程就是按照增强器的固定执行顺序(先前置,然后后置,最后返回或异常等)依次触发List中每个方法拦截器的执行,在该方法中使用了一个【责任链设计模式】调用。
一、拦截器链的创建过程
分析:上述代码中获取到的MathService 是一个被 Aop 增强之后的代理对象,通过对上述第9行的div方法进行断点debug,启动测试类之后,会进入到CglibAopProxy类的intercept方法(如需要查看源码,可以直接打开这个类即可,下面分析过程中省略一些非重点的代码)。该方法代码如下:
@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// ... 非重点代码暂时删除...
try {
Class<?> targetClass = (target != null ? target.getClass() : null);
// 创建将要执行的目标方法的拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 方法的返回值
Object retVal;
// 如果获取到的拦截器链是空的,即表示没有需要被增强的方法,则直接使用反射执行目标方法,并返回结果
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// 如果获取到拦截器链,则创建一个CglibMethodInvocation对象,并调用其proceed方法.
// 在proceed方法中,就会依次去链式执行所有增强之后的方法
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
}
}
那么拦截器链是如何创建的呢?即上述代码的第8行chain是如何生成的呢?继续查看其源代码,核心代码如下:
// 方法名称太长了,为了方便查看,此处简写一下
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
// 调用DefaultAdvisorChainFactory的get...Advice方法创建拦截器链,核心逻辑在该方法中
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
// 将生成的拦截器链缓存到methodCache中,使用的时候可以直接获取到.
this.methodCache.put(cacheKey, cached);
}
return cached;
}
上述通过调用advisorChainFactory的getInterceptorsAndDynamic…方法进行拦截器链的获取,然后将获取到的拦截器链缓存起来,方便下次使用的时候直接从缓存中获取。那么这个增强器工厂又是如何获取拦截器链的呢?继续打开advisorChainFactory的getInterceptors…方法,核心源码如下,在该方法中使用了一个【单例设计模式】来完成增强器适配器的初始化操作:
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
/**
* 实例化DefaultAdvisorAdapterRegistry,此处使用了饿汉式的【单例设计模式】。
*
* 实例化过程中,会去初始化三个增强器的适配器
*
* 初始化的三个增强器适配器:
* (1)MethodBeforeAdviceAdapter
* (2)AfterReturningAdviceAdapter
* (3)ThrowsAdviceAdapter
*/
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
Advisor[] advisors = config.getAdvisors();
// 用来保存最终的拦截器链的List,长度和增强器个数相同.
List<Object> interceptorList = new ArrayList<>(advisors.length);
// 被增强的类的真实Class类型
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
for (Advisor advisor : advisors) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
if (match) {
/** 根据增强器去获取增强器对应的方法拦截器,registry的默认实现类为:DefaultAdvisorAdapterRegistry */
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
从上述代码中可以看到,Spring中会首先获取到配置类中的所有增强器,然后挨个儿进行遍历,并将每一个增强器都转换为一个Interceptor对象,转换的过程中是调用registry对象的getInterceptors方法,这个方法中的处理逻辑在DefaultAdvisorAdaptorRegistry类中。逻辑如下:
(1)首先判断当前的增强器是否为MethodInterceptor类型,如果是,直接放入到interceptors数组中;
(2)然后通过循环所有的适配器,判断当前的增强器是否适配每种类型的适配器,判断方式就是使用instanceof判断当前对象是否为对应适配器接口的实例,使用了典型的【适配器设计模式】,适配完成之后,将转换的MethodInterceptor数组返回;源码如下:
@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<>(3);
Advice advice = advisor.getAdvice();
// 如果是MethodInterceptor类型的增强器,直接放入到interceptors集合中
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
// 如果不是MethodInterceptor类型的增强器,则使用增强器的适配器将其转换为MethodInterceptor,并放入到interceptors集合中
for (AdvisorAdapter adapter : this.adapters) {
/**
* adapters中包括了三种类型的适配器:
* (1)MethodBeforeAdviceAdapter:用于适配前置通知增强器的适配器
* (2)AfterReturningAdviceAdapter:用于适配返回通知增强器的适配器
* (3)ThrowsAdviceAdapter:用于适配异常通知增强器的适配器
*/
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[0]);
}
经过上述过程之后,将会把MathCalculator类中被增强器增强之后的方法封装为一个拦截器链,这个拦截器链其实就是一个list集合,里面放置的元素是由Advisor封装之后的方法拦截器对象MethodInterceptor。获取到拦截器链之后,然后调用CglibMethodInvocation对象的proceed()方法去触发整个拦截器链的执行。
二、拦截器链的执行过程
切面中定义的增强器按照执行顺序创建完方法拦截器链之后,最终生成的List类型拦截器链如下图所示:
其中包括了6个方法拦截器,分别如下:
(1)ExposeInvocationInterceptor:调用CglibMethodInvocation的proceed方法之后,该方法首先会被调用,用来将当前正在执行的方法拦截器对象ReflectiveMethodInvocation保存到一个ThreadLocal中,用于下次执行其他增强器时使用,代码如下:
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
// 从ThreadLocal中获取方法拦截器对象ReflectiveMethodInvocation
MethodInvocation oldInvocation = invocation.get();
invocation.set(mi);
try {
return mi.proceed();
}
finally {
invocation.set(oldInvocation);
}
}
(2)AspectJAfterThrowingAdvice:用来处理异常通知的方法拦截器
(3)AfterReturningAdviceInterceptor:用来处理返回通知的方法拦截器
(4)AspectJAfterAdvice:用来处理后置通知的方法拦截器
(5)AspectJAroundAdvice:用来处理环绕通知的方法拦截器
(6)MethodBeforeAdviceInterceptor:用来处理前置通知的方法拦截器
然后调用CglibMethodInvocation类的proceed方法去触发拦截器链中每一个方法拦截器的执行,proceed方法的核心源码如下:
@Override
@Nullable
public Object proceed() throws Throwable {
// currentInterceptorIndex初始默认值为-1,所以下面的if有两种情况下会直接执行:
// 当前在LogAspects切面类中有5个增强器,加上默认的ExposeInvocationInterceptor总共6个增强器
// (1)如果没有拦截器链,即拦截器链的size为0的时候,会执行,invokeJoinpoint()方法中会直接利用反射执行目标方法.
// (2)执行到了之后一个拦截器,即:currentInterceptorIndex为5的时候,也会执行目标方法.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 如果没有增强器,或者前置增强执行完毕,则会直接调用该方法利用反射执行目标方法
return invokeJoinpoint();
}
// 使用前自增(++currentInterceptorIndex)取出下一个增强器
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
/** 通知器或通知是动态匹配方法拦截器类型,自定义的默认增强点是不匹配这个类型的,会直接执行else逻辑 */
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
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 {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// 该方法中调用invoke方法,然后invoke方法中会再次调用proceed方法,然后又会回到该方法中.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
上述第10行,即invokeJoinpoint方法的逻辑就是使用反射执行目标方法,如下:
@Nullable
protected Object invokeJoinpoint() throws Throwable {
// 传入目标方法的参数,执行目标对象的目标方法
return AopUtils.invokeJoinpointUsingReflection(this.target,
this.method, this.arguments);
}
执行目标方法时,由自定义的增强器封装的方法拦截器链就会执行,即:调用上述proceed方法的第33行,这行代码以this为入参,即当前的ReflectiveMethodInvocation对象,然后执行invoke方法,会直接执行到ExposeInvocationInterceptor的invoke方法,该方法中会再次调用自身的proceed方法,然后又回到ReflectiveMethodInvocation类的proceed方法,这个时候currentInterceptorIndex会变为1,然后会从拦截器链集合中取出第2个方法拦截器,即:
AspectJAfterThrowingAdvice,然后在次调用ReflectiveMethodInvocation的invoke方法,将this作为入参,但是这时的this对象指的是AspectJAfterThrowingAdvice,所以会调用这个对象的invoke方法,这个类是用来处理异常通知的类,方法invoke中的核心代码如下:
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (Throwable ex) {
if (shouldInvokeOnThrowing(ex)) {
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}
可见,会再次调用proceed方法,然后又回到了ReflectiveMethodInvocation类的proceed方法中,然后methodInterceptorIndex又加1,取出下一个方法拦截器,即:AfterReturningAdviceInterceptor。然后在该类中再次调用proceed方法回到ReflectiveMethodInvocation中。methodInterceptorsIndex再次加1,然后调用下一个方法拦截器的invoke方法,如此循环。
直到执行AspectJAroundAdvice的invoke方法时,该方法中有执行逻辑,会直接使用放射去调用around增强器对应的增强方法。即:LogAspects中的doAround方法,然后将执行结果返回,如下:
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
JoinPointMatch jpm = getJoinPointMatch(pmi);
// 执行环绕通知@Around对应的方法,然后返回结果
return invokeAdviceMethod(pjp, jpm, null, null);
}
执行完Around之后,又会回到ReflectiveMethodInvocation类的proceed方法中,这个时候,取出的下一个方法拦截器是MethodBeforeAdviceInterceptor,会继续调用该方法拦截器对应的invoke方法,将当前的MethodReflectiveInvocation作为入参,传入到invoke方法中,然后执行MethodBeforeAdviceInterceptor的invoke方法,该方法中会执行before增强器对应的方法,即:logStart方法。然后返回之后,再次执行MethodReflectiveInvocation的proceed方法,这次执行的时候,methodInterceptorIndex的值已经增加到5,和拦截器链的长度减1,即:(this.interceptorsAndDynamicMethodMatchers.size() - 1)相等,所以会调用invokeJoinPoint(),即调用目标类MathCalculator的div方法。正常执行之后,会返回到上一个方法拦截器,即:AspectJAfterAdvice,然后执行after增强器对应的方法,即:logAfter方法。返回之后,如果正常,会再次回到AfterReturningAdviceInterceptor的invoke,如果异常,会回到AspectJAfterThrowingAdvice的invoke方法。
整个拦截器链的执行过程和web中的filter特别类似,和栈也特别类似,是在方法中调方法,执行到最内层的方法之后,再一层层向上返回执行外层方法,执行过程示意图如下:
上述流程图中,绿色线条代表了调用的过程,这个调用类似于入栈的过程,直到调用到了最底层的Around方法之后,开始一级一级向上返回,然后返回过程中,如果每异常,则执行返回通知,如果有异常则执行异常通知,上述流程执行完成之后,整个被增强的方法就执行完毕了。省略掉了AspectJAroundAdvice的调用,因为这个增强器是在调用前置通知Before之前,在目标方法执行完成之后,包裹了这两个过程,图中不好体现,略!
三、注解版AOP的原理总结
1、开启AOP功能,在配置类上声明@EnableAspectJAutoProxy注解
2、该注解会给容器中导入一个类型为AnnotationAwareAspectJAutoProxyCreateor类型的组件,这个组件是一个后置处理器,用来拦截Bean的创建,为需要增强的Bean生成代理对象;创建代理对象的过程中,提供了两种策略,一种是Cglib代理,一种是Jdk的动态代理,如果代理的不是接口,直接会使用cglib代理,也可以强制指定为cglib代理;
3、在执行目标bean的目标方法时,其实执行的是代理对象的方法,这个过程中,首先会将方法上应用的所有增强器封装为一个个的方法拦截器,然后放到一个List集合中,这个集合中的方法拦截器是有顺序的,这个集合称作拦截器链;然后下标去调用拦截器链中每个拦截器的invoke方法,逐级调用,最后逐级返回结果;执行过程中类似于一个压栈和出栈的过程!
4、执行顺序:环绕通知->前置通知->目标方法->环绕通知执行完成->后置通知->返回通知(如果有异常,则执行异常通知)
环绕通知是包裹了前置通知和目标方法的执行过程,目标方法执行完成之后,Around就执行完毕了。
至此!整个AOP介绍完毕!欢迎评论转发~