首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

基于注解的SpringAOP源码解析(一)

准备工作

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

代码语言:javascript
复制
https://github.com/shiyujun/spring-framework
Demo工程示例代码

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

代码语言:javascript
复制
<dependencies>
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-context</artifactId>
           <version>5.0.0.RELEASE</version>
       </dependency>
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-aop</artifactId>
           <version>5.0.0.RELEASE</version>
       </dependency>
       <dependency>
           <groupId>org.aspectj</groupId>
           <artifactId>aspectjrt</artifactId>
           <version>1.8.11</version>
       </dependency>
       <dependency>
           <groupId>org.aspectj</groupId>
           <artifactId>aspectjweaver</artifactId>
           <version>1.8.11</version>
       </dependency>
   </dependencies>

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

代码语言:javascript
复制
public interface IOCService {
    public String hollo();
}

public class IOCServiceImpl implements IOCService {
    public String hollo() {
        return "Hello,IOC";
    }
}

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

代码语言:javascript
复制
@EnableAspectJAutoProxy
@Configuration
public class AnnotationConfig {
    @Bean
    public IOCService iocService(){
        return new IOCServiceImpl();
    }
}

创建切点

代码语言:javascript
复制
@Aspect
@Component
public class AspectJTest {

    @Pointcut("execution(public * cn.shiyujun.service.IOCService.hollo(..))")
    public void testAOP(){}

    @Before("testAOP()")
    public void before(){
        System.out.println("before testAOP...");
    }

    @After("testAOP()")
    public void after(){
        System.out.println("after testAOP...");
    }

    @Around("testAOP()")
    public Object around(ProceedingJoinPoint p){
        System.out.println("around before testAOP...");
        Object o = null;
        try {
            o = p.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("around after testAOP...");
        return o;
    }
}

启动Spring

代码语言:javascript
复制
public class AnnotationIOCDemo {
    public static void main (String args[]){
        ApplicationContext context = new AnnotationConfigApplicationContext("cn.shiyujun.config");
        IOCService iocService=context.getBean(IOCService.class);
        System.out.println(iocService.hollo());
    }
}

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

@EnableAspectJAutoProxy注解

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

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

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

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

看一下这个配置类的操作

代码语言:javascript
复制
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
    AspectJAutoProxyRegistrar() {
    }

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
               //注册一个AOP代理实现的Bean,往下看          AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
        AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
        if (enableAspectJAutoProxy != null) {
            if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }

            if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
                AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
            }
        }

    }
}

registerAspectJAnnotationAutoProxyCreatorIfNecessary方法的主要功能是注册或者升级AnnotationAwareAspectJAutoProxyCreator

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

代码语言:javascript
复制
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); //如果已存在这个bean
        if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
            BeanDefinition apcDefinition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
            //判断优先级,如果优先级较高则替换原先的bean
            if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
                int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
                int requiredPriority = findPriorityForClass(cls);
                if (currentPriority < requiredPriority) {
                    apcDefinition.setBeanClassName(cls.getName());
                }
            }

            return null;
        } else {
            //注册AnnotationAwareAspectJAutoProxyCreator到容器中,此类负责基于注解的AOP动态代理实现
            RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
            beanDefinition.setSource(source);
            beanDefinition.getPropertyValues().add("order", -2147483648);
            beanDefinition.setRole(2);
            registry.registerBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator", beanDefinition);
            return beanDefinition;
        }
    }

未完待续 限于平台字数限制,本篇文章就到这里

举报
领券