[spring] 源码简析 aop(配置和注解)
本文从配置文件和注解两个角度介绍spring aop的具体实现。
配置文件方式AOP
spring.xml的配置文件中如下:
1 <aop:config> 2 <aop:aspect ref="aspectTx"> 3 <aop:pointcut id="pointcutId" expression="execution(* com.mian.aop.*.*(..))" /> 4 <aop:before pointcut-ref="pointcutId" method="start" /> 5 <aop:after-returning pointcut-ref="pointcutId" method="commit" /> 6 <aop:after-throwing pointcut-ref="pointcutId" method = "rollback"/> 7 </aop:aspect> 8 </aop:config>
构建BeanDefinition(Advisor)阶段
由前面的文章我们知道,在spring启动的时候,会解析xml文件,将beanDefinition注册到beanFactory中。对于命名空间是aop的节点会通过AopNamespaceHandler来解析节点。
标签和解析器的对应关系如下:
1public class AopNamespaceHandler extends NamespaceHandlerSupport { 2 3 public void init() { 4 registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser()); 5 registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser()); 6 registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator()); 7 registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser()); 8 } 9}
config标签最终由ConfigBeanDefinitionParser解析。
通过阅读源码可以知道:
-
会自动注册AspectJAwareAdvisorAutoProxyCreator的beanDefinition到beanDefinition
-
解析xml构造出AspectJPointcutAdvisor的RootBeanDefinition和切点的beanDefinition,将其注册到beanFactory中
先来看下结构如下:

构建以AspectJPointcutAdvisor为beanClass的RootBeanDefinition。
由于此RootBeanDefinition是需要注册到beanFactory中的,所以需要beanName。
spring给的命名规则是全类名#couner++自增。
以文章的配置文件为例,这里会创建三个这样的RootBeanDefinition。
分别对应aop:before和aop:after-returing和aop:after-throwing。
它的构造函数的参数是AbstractAspectJAdvice。
也是一个对象,所以构造函数的参数是RootBeanDefinition。
构造函数参数RootBeanDefinition的beanClass取决于配置文件中的定义。
它的属性值aspectName为aop:aspect的值。
构造函数有三个参数Method,切点,aop:aspect对象。
对应的也需要构造三个RootBeanDefinition。
你可能会问,为什么要创建这些BeanDefinition?
因为构建了BeanDefinition就可以根据bean的定义实例化对象了。aop最终就是要给满足切点条件的类创建代理类,就是通过Advisor来增强的。
构造函数参数①methodDef结构如下:

构造的RootBeanDefinition如下:

实现了BeanFactoryAware说明其实例化的过程,能够拿到beanFactory;根据targetBeanName从beanFactory中可以获取到beanDefinition,从而知道beanClass。根据methodName可以获取到具体的Method。
构造函数参数②pointcutDef结构如下:

构造的RootBeanDefinition如下:

这个类中的方法实现直接利用了现成的aspectj,给定express表达式构造出PointcutExpression。
提供matches方法,可以判定一个类是否符合这个切点的条件,或者一个方法是否符合这个切点的条件。
构造函数参数③aspectFactroyDef结构如下:

构造的RootBeanDefinition如下:

实现了BeanFactoryAware,知道aspectBeanName,可以直接获取到aop:aspect实例。
至此,已经构建好了Advisor的BeanDefintion,其中有三个要素(aop:aspect切面,切点,method)。后续在实例化bean的时候,会执行post-processor(比如AspectJAwareAdvisorAutoProxyCreator),是否为bean创建代理对象。
创建代理(利用Advisor)阶段
执行增强的契机是什么?
我们知道,实例化一个对象的时候,会首先根据构造函数实例化,然后设置其PropertyValue,最后会执行用户自定义的init方法。在这过程中有很多的钩子函数。
对bean进行增强的动作就是在init的方法之后。也就是post-processor的下面这段代码:
1// AbstractAutoProxyCreator 2 @Override 3 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 4 if (bean != null) { 5 Object cacheKey = getCacheKey(bean.getClass(), beanName); 6 if (!this.earlyProxyReferences.contains(cacheKey)) { 7 return wrapIfNecessary(bean, beanName, cacheKey); 8 } 9 } 10 return bean; 11 }
深入源码可以知道,首先会判断什么样的bean需要增强(参见表格)?

满足需要增强的条件,则开始创建代理,首先需要选择用哪种方式进行代理,我们知道spring提供了两种方式jdk or cglib?
1 @Override 2 public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { 3 if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { 4 Class<?> targetClass = config.getTargetClass(); 5 if (targetClass == null) { 6 throw new AopConfigException("TargetSource cannot determine target class: " + 7 "Either an interface or a target is required for proxy creation."); 8 } 9 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { 10 return new JdkDynamicAopProxy(config); 11 } 12 return new ObjenesisCglibAopProxy(config); 13 } 14 else { 15 return new JdkDynamicAopProxy(config); 16 } 17 }
下面我们来看Cglib的方式:
1 @Override 2 public Object getProxy(ClassLoader classLoader) { 3 if (logger.isDebugEnabled()) { 4 logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource()); 5 } 6 7 try { 8 Class<?> rootClass = this.advised.getTargetClass(); 9 Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy"); 10 11 Class<?> proxySuperClass = rootClass; 12 if (ClassUtils.isCglibProxyClass(rootClass)) { 13 proxySuperClass = rootClass.getSuperclass(); 14 Class<?>[] additionalInterfaces = rootClass.getInterfaces(); 15 for (Class<?> additionalInterface : additionalInterfaces) { 16 this.advised.addInterface(additionalInterface); 17 } 18 } 19 20 // Validate the class, writing log messages as necessary. 21 validateClassIfNecessary(proxySuperClass, classLoader); 22 23 // Configure CGLIB Enhancer... 24 Enhancer enhancer = createEnhancer(); 25 if (classLoader != null) { 26 enhancer.setClassLoader(classLoader); 27 if (classLoader instanceof SmartClassLoader && 28 ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) { 29 enhancer.setUseCache(false); 30 } 31 } 32 // ⭐️ 需要被代理的类 33 enhancer.setSuperclass(proxySuperClass); 34 enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); 35 enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); 36 enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader)); 37 // ⭐️ 增强,这就是利用advisor构建方法调用 38 Callback[] callbacks = getCallbacks(rootClass); 39 Class<?>[] types = new Class<?>[callbacks.length]; 40 for (int x = 0; x < types.length; x++) { 41 types[x] = callbacks[x].getClass(); 42 } 43 // fixedInterceptorMap only populated at this point, after getCallbacks call above 44 // ⭐️ 这是一个过滤器,哪些方法需要增强 45 enhancer.setCallbackFilter(new ProxyCallbackFilter( 46 this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); 47 enhancer.setCallbackTypes(types); 48 49 // Generate the proxy class and create a proxy instance. 50 return createProxyClassAndInstance(enhancer, callbacks); 51 } 52 catch (CodeGenerationException ex) { 53 } 54 catch (IllegalArgumentException ex) { 55 catch (Throwable ex) { 56 } 57 }
Cglib通过Enhancer创建代理类:
这里注意三个地方
-
给哪个类创建代理类 proxyTargetClass
-
执行的时候,哪些方法才需要代理
ProxyCallbackFilter.accept 只有返回结果是AOP_PROXY(0)的场合才进行aop代理
advisors中有任意切点mathches(proxyTargetClas, method),则需要增强。 -
方法的执行回调哪些方法 ==> getCallbacks
重点注意一下 DynamicAdvisedInterceptor.intercept,这里面会将Advisors中切点满足这个method的所有Advisors作为将要被应用的interceptors,来构建反射方法调用(CglibMethodInvocation)。
1 @Override 2 public Object proceed() throws Throwable { 3 // We start with an index of -1 and increment early. 4 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { 5 return invokeJoinpoint(); 6 } 7 8 Object interceptorOrInterceptionAdvice = 9 this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); 10 if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { 11 // Evaluate dynamic method matcher here: static part will already have 12 // been evaluated and found to match. 13 InterceptorAndDynamicMethodMatcher dm = 14 (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; 15 if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { 16 return dm.interceptor.invoke(this); 17 } 18 else { 19 // Dynamic matching failed. 20 // Skip this interceptor and invoke the next in the chain. 21 return proceed(); 22 } 23 } 24 else { 25 // It's an interceptor, so we just invoke it: The pointcut will have 26 // been evaluated statically before this object was constructed. 27 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); 28 } 29 }
代码的逻辑是这样的:
调用链模式,存在拦截器的场合,依次执行拦截器中的方法,之后回调回到该方法,继续判定是否有拦截器。所有拦截器都执行完毕,则执行方法原生的逻辑,然后一层层回调到拦截器中。
举个例子说明:
1// AspectJAfterAdvice 2 @Override 3 public Object invoke(MethodInvocation mi) throws Throwable { 4 try { 5 return mi.proceed(); 6 } 7 finally { 8 invokeAdviceMethod(getJoinPointMatch(), null, null); 9 } 10 } 11 12// MethodBeforeAdviceInterceptor 13 @Override 14 public Object invoke(MethodInvocation mi) throws Throwable { 15 this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() ); 16 return mi.proceed(); 17 }
这里一前一后两个拦截器,假设添加的拦截器的顺序是先after拦截器,再before拦截器。正确的执行结果,应该是before->原生method->after。
先执行AspectJAfterAdvice中的invoke,由于是后执行增强,所以回到CglibMethodInvocation.proceed。此时拦截器的位置是1,则执行MethodBeforeAdviceInterceptor中的invoke,执行before,然后调回到CglibMethodInvocation.proceed,发现拦截器执行完了,执行原生方法method后,回调到before拦截器中,然后回调到after拦截器中,继续执行after。
拦截器的添加顺序对最终的执行结果是没有影响的。
注解方式AOP
1 <context:component-scan base-package="com.mian.aop" />
2 <aop:aspectj-autoproxy/>
注解
1@Aspect 2@Component(value = "aspectTx") 3public class TransactionManager { 4 @Pointcut("execution(* com.mian.aop.*.*(..))") 5 public void pointcutId(){} 6 7 @Before(value = "pointcutId()") 8 public void start(){ 9 System.out.println("start tx"); 10 } 11 12 @AfterReturning(value = "pointcutId()") 13 public void commit(){ 14 System.out.println("commit tx"); 15 } 16 17 @AfterThrowing(value = "pointcutId()") 18 public void rollback(){ 19 System.out.println("rollback tx"); 20 } 21}
由xml配置文件的方式,我们知道大概的流程是先自动添加处理增强的post-processor,然后构建用于增强的Advisor的BeanDefinition,然后在钩子中给目标对象创建代理。
注解方式的大概流程也是如此。
1public class AopNamespaceHandler extends NamespaceHandlerSupport { 2 @Override 3 public void init() { 4 // In 2.0 XSD as well as in 2.1 XSD. 5 registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser()); 6 registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser()); 7 registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator()); 8 9 // Only in 2.0 XSD: moved to context namespace as of 2.1 10 registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser()); 11 } 12}
由上面的代码可以知道,aspect-autoproxy开启自动代理,最终用AspectJAutoProxyBeanDefinitionParser来解析。自动注册了AnnotationAwareAspectJAutoProxyCreator。它和配置文件方式自动注册的post-processor的关系是:

构建BeanDefinition(Advisor)阶段
注解方式是在什么时机构造Adivsor的?
spring容器启动过程中,会将AnnotationAwareAspectJAutoProxyCreator注册到beanFactory中。在实例化其他bean的过程中,会执行post-processors的方法。会判定是否需要给当前的bean创建代理类。判定的逻辑和配置文件aop的方式是一样的。
其中有个判定条件是遍历所有的Advisors,是否有任意的Advisors的切点matches(当前的bean)。该判定条件的前提,就是先要获取所有的Advisors对象。这就是创建的时机。
1// AnnotationAwareAspectJAutoProxyCreator 2 @Override 3 protected List<Advisor> findCandidateAdvisors() { 4 // Add all the Spring advisors found according to superclass rules. 5 List<Advisor> advisors = super.findCandidateAdvisors(); 6 // ⭐️ Build Advisors for all AspectJ aspects in the bean factory. 7 advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); 8 return advisors; 9 }
按照什么逻辑来构造Advisors的?
遍历beanFactory中的所有beanDefinition,找到其中beanClass是被@Aspect注解的beanName,注意这就是aspect切面。找到这个beanClass中没有被@Pointcut注解,但是被以下的注解注解的方法。
-
@Before
-
@Aroud
-
@After
-
@AfterReturing
-
@AfterThrowing
对满足以上条件的Method,一对一创建Advisor。
我们知道构造Advisors需要以下三信息:
-
切面aspect实例: 已知aspect的beanName,可以从beanFactory中获取。
-
切面方法: 上面已知
-
切点: 方法的注解中value 或者 pointcut的内容。
创建代理(利用Advisor)阶段
在给bean增强这点上,不管是配置文件的方式还是注解的方式,不管是发生的时机还是如何增强的方法都是一样的。
最后
补充一下用于增强的advice,发现其中有三个是直接实现了MethodInterceptor,有两个没有实现,最终是通过适配器,构建成MethodInterceptor。(这么做的原因我暂时没搞清楚) 如下:


总结下,配置文件中的标签,会自动注册的post-processors。
如下:

以上。
更多源码分析,关注公众号👇👇👇

浙公网安备 33010602011771号