在Spring中AOP是我们使用的非常频繁的一个特性。通过AOP我们可以补足一些面向对象编程中不足或难以实现的部分。
AOP 前置理论首先在学习源码之前我们需要了解关于AOP的相关概念如切点切面等,以及如何使用AOP,这里可以看我之前的文章:Spring系列之AOP的原理及手动实现
创建AOP相关对象对于Java这种面向对象语言来说任何功能的实现都是依赖于对象,AOP也不例外。
首先我们先来准备好在配置文件中配置好AOP相关的属性。
spring.xml
<bean/> <bean/> <aop:aspectj-autoproxy/> <aop:config> <aop:pointcut expression="execution(* cn.javass..*.sayAfterReturning(..))"></aop:pointcut> <aop:advisor pointcut="execution(* cn.javass..*.sayAdvisorBefore(..))" advice-ref="beforeAdvice"/> <aop:aspect ref="aspect"> <aop:before pointcut="execution(* cn.javass..*.sayBefore(..)) and args(param)" method="beforeAdvice(java.lang.String)" arg-names="param"/> <aop:after-returning pointcut-ref="pointcutA" method="afterReturningAdvice" arg-names="retVal" returning="retVal"/> <aop:after-throwing pointcut="execution(* cn.javass..*.sayAfterThrowing(..))" method="afterThrowingAdvice" arg-names="exception" throwing="exception"/> <aop:after pointcut="execution(* cn.javass..*.sayAfterFinally(..))" method="afterFinallyAdvice"/> <aop:around pointcut="execution(* cn.javass..*.sayAround(..))" method="aroundAdvice"/> </aop:aspect> </aop:config>在上面的配置中创建了几种不同的advice。这些配置在spring启动时会被相应的创建为对象。
AopNamespaceHandler在前面IOC文章中我们有提到在Spring中通过spi的机制来确定解析配置文件中不同标签的解析类。
在aop包中找到spring.handlers文件:
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler可以确定的是处理aop相关标签的就是AopNamespaceHandler这个类。
public void init() { this.registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser()); this.registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser()); this.registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator()); this.registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser()); }在AopNamespaceHandler中除了构造函数就只有上面的init方法,上面代码就是注册解析不同标签的解析器的BeanDefinition。我们需要关注的是aspectj-autoproxy标签的解析器类AspectJAutoProxyBeanDefinitionParser。
#### AopConfigUtils#registerOrEscalateApcAsRequired 跟踪```AspectJAutoProxyBeanDefinitionParser```的parse方法最终会进入到```AopConfigUtils#registerOrEscalateApcAsRequired```中。 private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); if (!cls.getName().equals(apcDefinition.getBeanClassName())) { int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); int requiredPriority = findPriorityForClass(cls); if (currentPriority < requiredPriority) { apcDefinition.setBeanClassName(cls.getName()); } } return null; } RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); beanDefinition.setSource(source); beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); return beanDefinition; } 这里的常量```AUTO_PROXY_CREATOR_BEAN_NAME = "org.springframework.aop.config.internalAutoProxyCreator";``` 首先要明白的是internalAutoProxyCreator并不是spring中的一个实际的类,AUTO_PROXY_CREATOR_BEAN_NAME是一个用于创建aop类的Beandefinition的名字。 在上面的代码逻辑中如果AUTO_PROXY_CREATOR_BEAN_NAME表示的Beandefinition已经存在则判断新需要注册的类其优先级和已经存在的类定义进行比较,如果新需要注册的优先级较高则进行替换。 如果不存在已经注册的Beandefinition则将其进行注册。被注册的Beandefinition表示的类为```AspectJAwareAdvisorAutoProxyCreator```。 #### 完成aop功能需要创建的对象 在前面IOC文章中分析过了在解析完配置文件后需要创建的对象都会将其BeanDefinition注册到IOC容器中,所以我们可以将断点设置在配置文件解析完成之后就可以看到需要创建那些对象了。 ![需要创建的对象](https://user-gold-cdn.xitu.io/2019/7/5/16bc0e4a57f8a819?w=789&h=405&f=png&s=22442) 如上图```helloWorldService```就是需要被增强的类。public interface IHelloWorldService {
void sayHello(); void sayBefore(String param); boolean sayAfterReturning(); void sayAfterThrowing(); boolean sayAfterFinally(); void sayAround(String param); void sayAdvisorBefore(String param);