本文将基于java-config(注解)研读 spring-AOP 源码
AOP的使用
配置类上添加
@EnableAspectJAutoProxy
注解 [开启AOP功能]AOP bean对象添加
@Aspect
注解@Aspect @Component public class AOPTest { @Pointcut("execution(* com.zhouxh.service.componentTest.*(..))") private void pointCut(){ } @Before(value = "pointCut()") public void before(){ System.out.println("aop Before start"); } @After(value = "pointCut()") public void after(){ System.out.println("aop After start"); } @Around(value = "pointCut()") public void around(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("aop Around start"); joinPoint.proceed(); System.out.println("aop Around end"); } @AfterReturning(value = "pointCut()") public void afterReturning(){ System.out.println("aop AfterReturning start"); } @AfterThrowing(value = "pointCut()") public void afterThrowing(){ System.out.println("aop AfterThrowing start"); } }
1. 加载切面
我们再开启AOP功能时,在配置类上添加了
@EnableAspectJAutoProxy
注解。该注解在配置类被解析时,会在spring容器中添加一个AnnotationAwareAspectJAutoProxyCreator
后置处理器。@EnableAspectJAutoProxy
进入该注解,我们可以看到该注解向spring 容器中注入了
AspectJAutoProxyRegistrar
类@Import(AspectJAutoProxyRegistrar.class) public @interface EnableAspectJAutoProxy {
进入
AspectJAutoProxyRegistrar
类,只有一个构造函数。
这个函数做了两件事情:- 在spring中注入了AnnotationAwareAspectJAutoProxyCreator后置处理器
- 判断是否设置proxyTargetClass 和 exposeProxy属性
- proxyTargetClass 属性,默认为false,如果为true时,表示相关bean对象动态代理强制使用CGLIB
- exposeProxy属性,默认为false,如果为true,有jdk动态代理生成bean对象出现方法内部调用时,也会触发AOP功能。
public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 在spring中注入了AnnotationAwareAspectJAutoProxyCreator后置处理器 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); // 获取注解@EnableAspectJAutoProxy AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class); if (enableAspectJAutoProxy != null) { // 判断是否设置proxyTargetClass 和 exposeProxy属性 if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } } }
在《spring IOC源码解析》这篇文章中,我们知道spring_bean第一次初始化会调用createBean()方法创建一个bean实例。在bean被创建【doCreateBean方法】前,通过spring提供的拓展点【resolveBeforeInstantiation方法】,将切点和通知包装成
Advisors
。protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { /** * 省略部分不相干代码 */ try { // spring 容器提供的拓展点,会在此处运行spring前置处理器 Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null) { return bean; } }catch (Throwable ex) {} try { // 创建一个bean实例 Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isTraceEnabled()) { logger.trace("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; }catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) { // 省略 }catch (Throwable ex) { // 省略 }
进入 resolveBeforeInstantiation方法,最终调用
applyBeanPostProcessorsBeforeInstantiation
方法循环调用所有的前置处理器。protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName); if (result != null) { return result; } } } return null; }
也就是在这里调用了我们在
@EnableAspectJAutoProxy
注解,给spring容器中添加的AnnotationAwareAspectJAutoProxyCreator
后置处理器。public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) { Object cacheKey = getCacheKey(beanClass, beanName); if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) { if (this.advisedBeans.containsKey(cacheKey)) { return null; } // isInfrastructureClass 判断当前beanClass是否被@Aspectj注释,是 返回true,否则返回false // AOP 类会被添加到缓存中,然后 保存在advisedBeans缓存中 // shouldSkip()方法解析各通知,并与切点一起包装成Advisors if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return null; } }
省略了部分代码 ``` return null;
}
`shouldSkip()`方法解析各通知,并与切点一起包装成`Advisors`。 ``` java protected boolean shouldSkip(Class<?> beanClass, String beanName) { // TODO: 查询所有的通知并添加到缓存中,方便调用时获取。 List<Advisor> candidateAdvisors = findCandidateAdvisors(); for (Advisor advisor : candidateAdvisors) { // 判断AOP是否是通过xml配置的,如果是返回true 【为了兼容xml】 if (advisor instanceof AspectJPointcutAdvisor && ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) { return true; } } return super.shouldSkip(beanClass, beanName); }
findCandidateAdvisors()
方法查询所有的通知并添加到缓存中,方便调用时获取。protected List<Advisor> findCandidateAdvisors() { // 查找所有继承了 Advisor.class的类【我们通过注解的形式,所以此处查询为空】 List<Advisor> advisors = super.findCandidateAdvisors(); // Build Advisors for all AspectJ aspects in the bean factory. if (this.aspectJAdvisorsBuilder != null) { // 真正生效的是 buildAspectJAdvisors() 解析变创建 advisors advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors; }
通过
aspectJAdvisorsBuilder.buildAspectJAdvisors()
创建advisors并添加到缓存中。- this.advisorFactory.getAdvisors(factory)通过 解析切面类中方法上的注解 获取通知 和 切点一起封装到advisor中,将所有
advisors
根据 Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 的顺序进行排序。 - 并将adviors保存在
advisorsCache
缓存中public List<Advisor> buildAspectJAdvisors() { ··· 此处省略部分判断代码 ··· // 通过解析class类中的方法上的注解 根据 Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 排序 List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory); if (this.beanFactory.isSingleton(beanName)) { // 将通知和切点 与 当前bean 一起保存在advisorsCache 缓存中 this.advisorsCache.put(beanName, classAdvisors); } ··· 此处省略部分代码 ··· }
- this.advisorFactory.getAdvisors(factory)通过 解析切面类中方法上的注解 获取通知 和 切点一起封装到advisor中,将所有
2. 创建代理
spring_bean被创建大致可以分为三步:1. bean的实例化;2. bean属性的注入;3. bean的初始化
AOP 创建动态代理在第三步:bean的初始化【exposedObject = initializeBean(beanName, exposedObject, mbd);
】
在bean的初始化完成之后,spring提供了一个调用后置处理器的拓展点,就在此处spring会调用AnnotationAwareAspectJAutoProxyCreator
后置处理器的后置处理方法。
让我们来追溯源码!
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
···
省略部分代码:完成spring_bean的初始化工作
···
// 在这之前,bean的初始化已经完成。
// spring提供的拓展点,调用后置处理器的后置处理方法
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
在applyBeanPostProcessorsAfterInitialization
方法中循环所有后置处理器并调用对应的后置处理方法。
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
getBeanPostProcessors()
获取所有的后置处理器,其中就有 AnnotationAwareAspectJAutoProxyCreator
通过调用父类AbstractAutoProxyCreator.postProcessAfterInitialization()
方法 —> 最终调用wrapIfNecessary()
方法生成动态代理。
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 不需要AOP增强的类,直接返回原始对象,不需要动态代理
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 再次判断是否需要增强,不需要的直接返回
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 如果需要AOP 增强,创建动态代理
// 通过 AspectJ 的 api 判断当前类中哪些方法符合哪些通知【通过切点表达式,选择需要增强的内容】
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建动态代理
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
看到这里我们还有一个疑问:AOP动态代理是怎么选择JDK动态代理 还是 CGLIB动态代理的?
继续跟进createProxy()
方法,最终进入DefaultAopProxyFactory.createAopProxy()
方法
- isProxyTargetClass() —-> 我们在@EnableAspectJAutoProxy()注解中设置 proxyTargetClass = true;
@EnableAspectJAutoProxy(proxyTargetClass = true)
- hasNoUserSuppliedProxyInterfaces() —-> true 表示 当前增强类没有实现任何接口
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } // 如果目标增强类,是一个接口 或者 是一个代理类 也会使用JDK动态代理 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } }
看完这部分代码我们也能得出上面问题的答案了
- 如果在开启AOP的注解
@EnableAspectJAutoProxy(proxyTargetClass = true)
中添加了proxyTargetClass = true
,那么spring会使用CGLIB动态代理。 - 如果目标增强类没有继承任何接口,那么spring会使用CGLIB动态代理。
- 如果目标增强类,是一个接口或者是一个代理类,也会使用JDK动态代理
- 否则,会使用JDK动态代理
3. 调用代理
我们知道被代理类的方法被执行时,会先调用代理类的代理方法【jdk动态代理的invoke()/CGLIB动态代理的intercept()】。
我们将以CGLIB动态代理为例,研读Spring AOP是如果调用代理的。
当被增强类的方法被执行时,spring会先调用CglibAopProxy的内部类DynamicAdvisedInterceptor.intercept()方法
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);
// 加载切面时,封装好的adviors集合
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// 如果没有封装好的adviors,直接调用对应方法
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// AOP 执行通知的入口
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(); 该方法是 AOP 执行通知的入口。
public Object proceed() throws Throwable {
// currentInterceptorIndex 初始化时为 -1
// 如果执行到AOP中声明的最后一个通知,调用目标方法。
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 调用目标增强方法
return invokeJoinpoint();
}
// interceptorsAndDynamicMethodMatchers 包含所有的通知的集合,每次获取下一个通知
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// 省略部分代码
}else {
// 在此处调用对应通知的对应类
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
invoke()方法会更根据下图顺序依次调用。interceptorsAndDynamicMethodMatchers
中的对象
调用时序图
环绕通知类 - AspectJAroundAdvice
该类没有什么特殊的方法,就是调用AOP中被@Around注释的方法
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);
// 调用环绕通知方法
return invokeAdviceMethod(pjp, jpm, null, null);
}
在环绕通知方法中,先进行前置通知,然后唤醒一个通知,最后进行后置通知。
@Around(value = "pointCut()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("aop Around start");
joinPoint.proceed();
System.out.println("aop Around end");
}
前置通知 - MethodBeforeAdviceInterceptor
先调用AOP中被@Before注释的方法,然后唤醒下一通知
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
后置通知 - AspectJAfterAdvice
先唤醒下一通知,再调用AOP中被@After注释的方法。
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
后置返回通知 - AfterReturningAdviceInterceptor
唤醒下一通知,再调用AOP中被@AfterReturning注释的方法。
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
后置异常通知 - AspectJAfterThrowingAdvice
先执行下一通知,如果出现异常,再执行@AfterThrowing注释的方法。
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (Throwable ex) {
if (shouldInvokeOnThrowing(ex)) {
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}
在唤醒下一通知前,会判断是否存在下一通知,如果不存在,直接调用目标增强方法。
该判断在ReflectiveMethodInvocation.proceed()
方法中
public Object proceed() throws Throwable {
// currentInterceptorIndex 初始化时为 -1
// 如果执行到AOP中声明的最后一个通知,调用目标方法。
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 调用目标增强方法
return invokeJoinpoint();
}
····
····
}
总结
spring会在doCreateBean之前,会调用 spring 提供的拓展点【resolveBeforeInstantiation】,从所有 beanDefinitionMap 中获取所有的 Object 类型的类,循环判断并获取哪个类被 @Aspectj 注解注释。然后解析该类中被 @Before、@After、@Around、@AfterReturning、@AfterThrowing 注解注释的方法,并与 @Pointcut 注释的切点一起封装在 adviors 中。
在 spring 初始化方法中,调用所有后置处理器的后置处理方法,获取所有的 adviors 和当前类进行匹配【匹配方法是调用AspectJ的内部API】。匹配成功的类再由 AOPProxyFactory 根据【是否有接口、是否有proxyTargetClass = true】选择使用CGLIB动态代理还是JDK动态代理。
在目标增强方法被执行时,spring 会将adviors转换成Interceptor,然后通过责任链的模式一次进行调用。