专栏首页Java学习录基于注解的SpringAOP源码解析(一)

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

准备工作

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

https://github.com/shiyujun/spring-framework
Demo工程示例代码

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

<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源码解析那几篇文章用的同一个工程,所以没有改名字

public interface IOCService {
    public String hollo();
}

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

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

@EnableAspectJAutoProxy
@Configuration
public class AnnotationConfig {
    @Bean
    public IOCService iocService(){
        return new IOCServiceImpl();
    }
}

创建切点

@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

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管理

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

看一下这个配置类的操作

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注解定义的切点来自动代理与表达式匹配的类。 下面看一个这个实现的逻辑

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;
        }
    }

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

本文分享自微信公众号 - Java学习录(Javaxuexilu),作者:石玉军

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-08-14

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 使用SpringBoot2.0.3整合SpringCloud

    在刚刚新建的父项目下新增一个项目cloud-demo-provider,引入web依赖。

    Java学习录
  • SpringMVC源码解析(一)

    为了简单起见,再一个就是现在这个年代也没有啥项目使用JSP了。所以本次分析使用SpringBoot结合thymeleaf来搞

    Java学习录
  • Ribbon架构剖析

    在学习Ribbon之前,先看一下这张图,这张图完美的把Ribbon的基础架构给描述出来了

    Java学习录
  • .NET Core采用的全新配置系统[6]: 深入了解三种针对文件(JSON、XML与INI)的配置源

    物理文件是我们最常用到的原始配置的载体,最佳的配置文件格式主要由三种,它们分别是JSON、XML和INI,对应的配置源类型分别是JsonConfiguratio...

    蒋金楠
  • Java 访问权限控制 小结

    总所周知,Java提供了访问权限修饰词,以供类库开发人员向客户端程序员指明哪些是可用的,哪些是不可用的。

    Rekent
  • Z.ExtensionMethods 一个强大的开源扩展库

    今天有意的在博客园里面搜索了一下 Z.ExtensionMethods 这个扩展类库,确发现只搜到跟这个真正相关的才两篇博文而已,我都点进去看了一下,也都只是提...

    逸鹏
  • Spring Boot 优雅的配置拦截器方式

    其实spring boot拦截器的配置方式和springMVC差不多,只有一些小的改变需要注意下就ok了。下面主要介绍两种常用的拦截器:

    kinbug [进阶者]
  • 23种设计模式详解(五)

    南风
  • 面试必备【含答案】Java面试题系列(二)

    答:GC 是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,...

    苏先生
  • 异常中要了解的Throwable类中的几个方法

    *   public String getMessage()   获取异常的信息,返回的是字符串

    黑泽君

扫码关注云+社区

领取腾讯云代金券