文章结构

阅读本篇文章之前建议您首先查看上方两篇文章,因为本篇主要是描述了基于注解的方式和基于xml配置文件方式的异同点

  1. 源码阅读环境的搭建
  2. 首先简单描述了bean容器AnnotationConfigApplicationContext
  3. 然后源码执行的第一步就是关于包扫描一块的东西,也就是我们比较熟悉的注解@ComponentScan
  4. 扫描到了各个带有注解的类之后就是读取类呀、反射呀什么的来加载类
  5. bean已经加载完后就是bean的注册逻辑了
    相比较与之前两篇文章的长篇大论,这篇文章的篇幅要少很多,这主要得益于Spring的设计精妙和代码之优雅

    准备工作

本文会分析Spring的AOP模块的整体流程,分析过程需要使用一个简单的demo工程来启动Spring,demo工程我以备好,需要的童鞋自行在下方链接下载:

  1. https://github.com/shiyujun/spring-framework

Demo工程示例代码

本文源码分析基于Spring5.0.0,所以pom文件中引入5.0的依赖

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-context</artifactId>
  5. <version>5.0.0.RELEASE</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.springframework</groupId>
  9. <artifactId>spring-aop</artifactId>
  10. <version>5.0.0.RELEASE</version>
  11. </dependency>
  12. <dependency>
  13. <groupId>org.aspectj</groupId>
  14. <artifactId>aspectjrt</artifactId>
  15. <version>1.8.11</version>
  16. </dependency>
  17. <dependency>
  18. <groupId>org.aspectj</groupId>
  19. <artifactId>aspectjweaver</artifactId>
  20. <version>1.8.11</version>
  21. </dependency>
  22. </dependencies>

然后写一个简单的接口和实现类,跟IOC源码解析那几篇文章用的同一个工程,所以没有改名字

  1. public interface IOCService {
  2. public String hollo();
  3. }
  4. public class IOCServiceImpl implements IOCService {
  5. public String hollo() {
  6. return "Hello,IOC";
  7. }
  8. }

增加bean的配置类,以及启动AOP

  1. @EnableAspectJAutoProxy
  2. @Configuration
  3. public class AnnotationConfig {
  4. @Bean
  5. public IOCService iocService(){
  6. return new IOCServiceImpl();
  7. }
  8. }

创建切点

  1. @Aspect
  2. @Component
  3. public class AspectJTest {
  4. @Pointcut("execution(public * cn.shiyujun.service.IOCService.hollo(..))")
  5. public void testAOP(){}
  6. @Before("testAOP()")
  7. public void before(){
  8. System.out.println("before testAOP...");
  9. }
  10. @After("testAOP()")
  11. public void after(){
  12. System.out.println("after testAOP...");
  13. }
  14. @Around("testAOP()")
  15. public Object around(ProceedingJoinPoint p){
  16. System.out.println("around before testAOP...");
  17. Object o = null;
  18. try {
  19. o = p.proceed();
  20. } catch (Throwable e) {
  21. e.printStackTrace();
  22. }
  23. System.out.println("around after testAOP...");
  24. return o;
  25. }
  26. }

启动Spring

  1. public class AnnotationIOCDemo {
  2. public static void main (String args[]){
  3. ApplicationContext context = new AnnotationConfigApplicationContext("cn.shiyujun.config");
  4. IOCService iocService=context.getBean(IOCService.class);
  5. System.out.println(iocService.hollo());
  6. }
  7. }

至此,demo工程准备完毕。我就不详细的说明了,直接开始看源码吧

@EnableAspectJAutoProxy注解

可以看到,在最开始的demo工程中,为了开启AOP功能,我使用了一个@EnableAspectJAutoProxy注

进入这个注解可以查看到这个注解的2个属性,相信大家都已经很熟悉了,就不相信的说明了。除此之外可以看到这个注解使用@Import注解引入了一个配置类

@Import注解:可以引入一个类,将这个类注入到Spring IOC容器中被当前Spring管理

  1. @Import(AspectJAutoProxyRegistrar.class)
  2. public @interface EnableAspectJAutoProxy {
  3. //proxyTargetClass属性,默认false,尝试采用JDK动态代理织入增强(如果当前类没有实现接口则还是会使用CGLIB);如果设为true,则强制采用CGLIB动态代理织入增强
  4. boolean proxyTargetClass() default false;
  5. //通过aop框架暴露该代理对象,aopContext能够访问。为了解决类内部方法之间调用时无法增强的问题
  6. boolean exposeProxy() default false;
  7. }

看一下这个配置类的操作

  1. class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
  2. AspectJAutoProxyRegistrar() {
  3. }
  4. public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
  5. //注册APC bean : AnnotationAwareAspectJAutoProxyCreator
  6. AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
  7. //从导入者类上获取注解@EnableAspectJAutoProxy的属性,根据其中的 proxyTargetClass/exposeProxy, 对所创建的 APC 做设置
  8. AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
  9. if (enableAspectJAutoProxy != null) {
  10. if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
  11. AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
  12. }
  13. if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
  14. AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
  15. }
  16. }
  17. }
  18. }

registerAspectJAnnotationAutoProxyCreatorIfNecessary() 方法的主要功能是注册或者升级AnnotationAwareAspectJAutoProxyCreator类 (这个类有多个优先级的实现)

这个类在AOP中非常的重要,它的主要功能就是根据@Point注解定义的切点来自动代理与表达式匹配的类。
下面看一个这个实现的逻辑

  1. private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
  2. Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); //如果已存在这个bean
  3. if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
  4. BeanDefinition apcDefinition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
  5. //判断优先级,如果优先级较高则替换原先的bean
  6. if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
  7. int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
  8. int requiredPriority = findPriorityForClass(cls);
  9. if (currentPriority < requiredPriority) {
  10. apcDefinition.setBeanClassName(cls.getName());
  11. }
  12. }
  13. return null;
  14. } else {
  15. //注册AnnotationAwareAspectJAutoProxyCreator到容器中,此类负责基于注解的AOP动态代理实现
  16. RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
  17. beanDefinition.setSource(source);
  18. beanDefinition.getPropertyValues().add("order", -2147483648);
  19. beanDefinition.setRole(2);
  20. registry.registerBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator", beanDefinition);
  21. return beanDefinition;
  22. }
  23. }