所有分类
  • 所有分类
  • 未分类

Spring之AOP的原理(一)-概述

简介

说明

本文介绍Spring中的AOP的原理。

相关网址

Spring之AOP的原理(二)–源码分析 – 自学精灵

原理概述

原理简介

Spring AOP本质是用的代理模式(动态代理),其基于BeanPostProcessor实现,从而能够与IOC结合起来。

引入AOP的方法

如果引入的是spring-aop包,则需要使用@EnableAspectJAutoProxy开启aop功能;如果引入的是spring-boot-starter-aop,则AOP就直接可以用了,无需加注解之类的开启它。 

  • spring-boot-starter-aop  (此包里包含了spring-aop与aspectjweaver)
    • spring-aop:AOP核心功能,例如代理工厂等等
    • aspectjweaver:支持切入点表达式、aop相关注解等。(本依赖包含aspectjrt)
      • aspectjrt:支持aop相关注解等。

AOP的启用

导入包即可,默认开启:spring.aop.auto=true  //等价于@EnableAspectJAutoProxy

JDK代理与CGLIB代理

SpringBoot 1.5.x:默认使用JDK代理,即:spring.aop.proxy-target-class=false  若设置为true,则使用CGLIB动态代理。
SpringBoot 2.x:默认使用CGLIB代理,即:spring.aop.proxy-target-class=true。

对应的自动配置类为:org.springframework.boot.autoconfigure.aop.AopAutoConfiguration

为什么SpringBoot 2.x:默认使用CGLIB代理?

见spring的issue:Use @EnableTransactionManagement(proxyTargetClass = true) · Issue #5423 · spring-projects/spring-boot · GitHub

即:我们应该使用@EnableTransactionManagement(proxyTargetClass = true)来防止人们不使用接口时出现讨厌的代理问题。

讨厌的代理问题

假设,我们有一个UserServiceImpl和UserService类,此时需要在UserContoller中使用UserService。在 Spring 中通常都习惯这样写代码:

@Autowired
UserService userService;

在这种情况下,无论是使用 JDK 动态代理,还是 CGLIB 都不会出现问题。

但是,如果你的代码是这样的呢:

@Autowired
UserServiceImpl userService;

这个时候,如果我们是使用 JDK 动态代理,那在启动时就会报错:

类的关系

版本

本文的版本:springboot:2.3.0.RELEASE;Spring:5.2.6.RELEASE。

AOP的核心类的分类

advisorCreator,继承 spring ioc的扩展接口 BeanPostProcessor,主要用来扫描获取 advisor。
advisor:通知者,封装了spring aop中的切点和通知。 就是我们常用的@Aspect 注解标记的类。
advice: 通知,也就是aop中增强的方法。

AnnotationAwareAspectJAutoProxyCreator

  • 实现了Order接口,所以先于普通的BeanPostProcessor注册,并对普通BeanPostProcessor也能起作用。
  • 实现了InstantiationAwareBeanPostProcessor接口,所以会在Bean被创建之前被调用。

Spring Aop主要是通过AbstractAutoProxyCreator实现的BeanPostProcessor、InstantiationAwareBeanPostProcessor以及SmartInstantiationAwareBeanPostProcessor接口里面的后置处理器方法,来介入到Spring IOC容器的Bean的实例化以及初始化的过程中对Bean进行AOP的处理的。所以AbstractAutoProxyCreator类实现的容器级别的后置处理器方法是介入分析的点。

总览

  • AbstractAutoProxyCreator:Spring 为Spring AOP 模块暴露的可扩展抽象类,也是 AOP 中最核心的抽象类。
  • BeanNameAutoProxyCreator:根据指定名称创建代理对象(阿里连接池框架druid也基于此类做了扩展)。通过设置 advisor,可以对指定的 beanName 进行代理。支持模糊匹配。
  • AbstractAdvisorAutoProxyCreator:功能比较强大,默认扫描所有Advisor的实现类。相对于根据Bean名称匹配,该类更加灵活。动态的匹配每一个类,判断是否可以被代理,并寻找合适的增强类,以及生成代理类。
  • DefaultAdvisorAutoProxyCreator:AbstractAdvisorAutoProxyCreator的默认实现类。可以单独使用,在框架中使用AOP,尽量不要手动创建此对象。
  • AspectJAwareAdvisorAutoProxyCreator:Aspectj的实现方式,也是Spring Aop中最常用的实现方式,如果用注解方式,则用其子类AnnotationAwareAspectJAutoProxyCreator。
  • AnnotationAwareAspectJAutoProxyCreator:目前最常用的AOP使用方式。spring aop 开启注解方式之后,该类会扫描所有@Aspect()注释的类,生成对应的advisor。目前SpringBoot框架中默认支持的方式,自动配置。本文我们就分析此类。

简要流程

开启AOP功能

AopAutoConfiguration实现Aop的自动装配,配置好依赖就能直接使用。此时有@EnableAspectJAutoProxy,开启AspectJ的代理功能。

AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar,实现registerBeanDefinitions方法
registerBeanDefinitions方法:向容器中注册bean:org.springframework.aop.config.internalAutoProxyCreator=AnnotationAwareAspectJAutoProxyCreator

创建代理类对象 

AnnotationAwareAspectJAutoProxyCreator实现生命周期监听,后置处理AspectJ切入的类,查找缓存所有的Advisors,创建代理类对象。具体步骤如下:

  1. 解析和加载横切逻辑:AbstractAutoProxyCreator#postProcessBeforeInstantiation方法(在Bean实例化之前被调用)。
  2. 创建代理类:AopProxy创建代理类(目标Bean)。
  3. 将横切逻辑织入代理类(目标Bean):
    1. 代理类里面会插入Advisor注解的方法中的代码
    2. 方法是:AbstractAutoProxyCreator#postProcessAfterInitialization方法(在Bean实例化之后被调用)。

DefaultAopProxyFactory提供代理策略,接口走JDK代理,类走Cglib代理。SpringBoot默认走Cglib代理。

执行目标方法

代理对象中的proxyFactory包含增强器和目标对象。

  1. 目标方法执行
  2. CglibAopProxy.intercept()
  3. 遍历所有的增强器,将其转为Interceptor,利用MethodInterceptor机制生成拦截器链
    1. 如果有拦截器链,把需要执行的目标对象,目标方法,拦截器链等信息传入创建一个CglibMethodInvocation 对象
    2. 调用mi.proceed(),链式获取每一个拦截器
    3. 拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行;

拦截器链的机制,保证通知方法与目标方法的执行顺序。

3

评论0

请先

显示验证码
没有账号?注册  忘记密码?

社交账号快速登录