深入理解Spring之AOP

 2023-01-21
原文作者:现在没有牛仔了 原文地址:https://juejin.cn/post/7177346219755175994

什么是AOP

AOP(面向切面)编程,是一种编程思想;是对面向对象编程OOP的一种增强,OOP是纵向对一个事物的抽象。而AOP是横向的对不同事物的抽象、抽取,而用这种思维去设计编程的方式叫做面向切面编程。

相关概念

  • Target(目标对象)

    • 需要被增强的方法所在的对象
  • Proxy(代理对象)

    • 对目标对象进行增强后的对象
  • Joinpoint(连接点)

    • 目标对象中 可以 被增强的方法
  • Pointcut(切入点)

    • 目标对象中 实际 被增强的方法
  • Advice(通知/增强)

    • 增强部分的代码逻辑
  • Aspect(切面)

    • 增强部分和切入点的组合
  • Weaving(织入)

    • 将通知和切入点动态组合的过程

202301011955240961.png

上图所示是一个AOP的架构,现有一个 目标对象 A,对象A中有三个方法可以被增强,也就是说有三个 连接点 ;现在想要增强的方法是methodA1、methodA2,所以这两个方法就是 切入点 ;我们要使用对象B中的两个方法做一个增强,所以methodB1、methodB2就是 增强 的具体代码;最后我们将切点与增强的代码组合在一起就形成了一个 切面 并存储到代理对象的具体方法中。现在通过调用代理对象的方法就可以执行增强后的methodA1、methodA2。

在Spring中通过注解实现AOP

导入依赖

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>

在配置类中添加@EnableAspectJAutoProxy注解

    @Configuration
    @ComponentScan("com.demo")
    @EnableAspectJAutoProxy //开启切面自动代理(开启AOP功能)
    public class SpringConfig {}

目标对象

    @Component
    public class User {
        @Autowired
        private Pets pets;
    
        //切入点
        void petEat(){
            pets.eat();
        }
    }

定义切面、编写增强方法、配置切入点

    @Component
    @Aspect //定义切面
    public class MyAspect {
        //配置切入点 @Before:前置增强
        @Before(value = "execution(* com.demo.User.petEat(..))")
        public void sayHello(){ //编写增强方法
            System.out.println("hello");
        }
    }

运行结果

    hello
    大黄开始吃东西了

AOP运行原理

  1. @EnableAspectJAutoProxy注解会导入AspectJAutoProxyRegistrar
    @EnableAspectJAutoProxy //开启切面自动代理(开启AOP功能)
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import({AspectJAutoProxyRegistrar.class})
    public @interface EnableAspectJAutoProxy {
        boolean proxyTargetClass() default false;
    
        boolean exposeProxy() default false;
    }
  1. 紧接着会注册一个AnnotationAwareAspectJAutoProxyCreator到容器中,继承体系中包含BeanPostProcessor后处理器,在 postProcessAfterInitialization 中筛选出需要被增强的bean,创建代理对象

    202301011955245582.png

202301011955249863.png

BeanPostProcessor后处理器:后处理器postProcessAfterInitialization方法,会在Bean创建实例并初始化之后,填充到单例池singletonObjects之前执行。在这个阶段可以对指定的对象进行扩展。

动态代理的两种方式

  • JDK动态代理

    • 使用条件:目标类有接口,实现原理是基于接口动态生成实现类的代理对象
    • 在spring中,如果目标类有接口,默认使用JDK动态代理
  • Cglib动态代理

    • 使用条件:目标类没有接口并且不能使用final修饰,实现原理是基于被代理对象动态生成子对象为代理对象
    • 在spring中,目标类如果没有接口,默认使用Cglib动态代理。
    • 强制使用:如果目标类有接口,仍需使用Cglib,可以通过配置proxy-target-class="true"强制使用
            @EnableAspectJAutoProxy(proxyTargetClass = true)