SpringAOP 快速入门 : 

https://blog.csdn.net/Boop_wu/article/details/161120508?fromshare=blogdetail&sharetype=blogdetail&sharerId=161120508&sharerefer=PC&sharesource=Boop_wu&sharefrom=from_linkhttps://blog.csdn.net/Boop_wu/article/details/161120508?fromshare=blogdetail&sharetype=blogdetail&sharerId=161120508&sharerefer=PC&sharesource=Boop_wu&sharefrom=from_link

三.Spring AOP 原理

1.代理模式 :

为目标对象创建一个代理对象 , 由代理对象控制目标对象的访问 , 并做增强

代理模式的主要角色 :

  • Subject : 业务接口类
  • RealSubject : 业务实现类
  • Proxy : 代理类

代理模式 分为静态代理和动态代理(JDK 动态代理 , CGLIB 动态代理)

1.1 静态代理

在程序运行前 , dialing 类的.class 文件就已经存在了

业务接口
public interface HouseSubject {
    void rentHouse();
}
目标类
public class RealHouseSubject implements HouseSubject{
    @Override
    public void rentHouse() {
        System.out.println("房东出租房子");
    }
}
代理类
public class HouseProxy implements HouseSubject {
    private HouseSubject target;
    public HouseProxy(HouseSubject target) {
        this.target = target;
    }
    @Override
    public void rentHouse() {
        System.out.println("开始代理");
        target.rentHouse();
        System.out.println("结束代理");
    }
}
缺点 :

一个接口一个代理类 , 不灵活 , 无法通用

1.2 动态代理(AOP 核心)

① JDK 动态代理(必须有接口)
实现步骤 :
  1. 定义一个接口及其实现类
  2. 自定义 InvocationHandler 并重写 invoke 方法 , 在 invoke 方法中我们会调用目标方法并自定义一些处理逻辑
  3. 通过 Proxy.newProxyInstance(ClassLoader loader , Class<?>[] interfaces,InvocationHandler h) 方法创建代理对象
实现 InvocationHandler 接口
public class JDKInvocationHandler implements InvocationHandler {
    //目标对象就是被代理对象
    private Object target;
    public JDKInvocationHandler(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //代理增强内容
        System.out.println("我是中介,开始代理");
        Object result = method.invoke(target, args);
        System.out.println("我是中介,结束代理");
        return result;
    }
}
创建代理对象
public class DynamicMain {
    public static void main(String[] args) {
        HouseSubject target = new RealHouseSubject();
        HouseSubject proxy = (HouseSubject) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                new Class[]{HouseSubject.class},
                new JDKInvocationHandler(target)
        );
    }
}
解析 :
  1. InvocationHandler

InvocationHandler 接口是 Java 动态代理的关键接口之一 , 它定义了一个单一的方法 invoke() , 用于处理被代理对象的方法调用

  1. Proxy

  • newProxyInstance() , 这个方法主要用来生成一个代理对象 ; 这个方法共有三个参数 :
  • loder : 类加载器 , 用于加载代理对象
  • interfaces : 被代理类实现的一下接口(意味着 JDK 动态代理只能代理已经实现了接口的一些类)
  • h : 实现了 InvocationHandler 接口的对象

②CGLIB 动态代理(无接口也能代理)

Code Generation Library : 是一个基于 ASM 的字节码生成库 , 它允许我们在运行时对字节码进行修改和动态生成 ; 生成目标类的字类作为代理 ; 无需接口

实现步骤 :
  1. 定义一个类
  2. 自定义 MethodIntercepter 并重写 interceptor
添加依赖
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>
自定义 MethodInterceptor(方法拦截器)
public class CGLIBInterceptor implements MethodInterceptor {
    //⽬标对象, 即被代理对象 
    private Object target;

    public CGLIBInterceptor(Object target) {
        this.target = target;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        // 代理增强内容 
        System.out.println("我是中介, 开始代理");
        //通过反射调⽤被代理类的⽅法 
        Object retVal = methodProxy.invoke(target, objects);
        //代理增强内容 
        System.out.println("我是中介, 代理结束");
        return retVal;
    }
}
创建类
public class DynamicMain {
    public static void main(String[] args) {
        HouseSubject target = new RealHouseSubject();
        HouseSubject proxy = (HouseSubject) Enhancer.create(target.getClass(), new CGLIBInterceptor(target));
        proxy.rentHouse();
    }
}
解析 :
  1. MethodInterceptor : 和 JDK 动态代理中的 InvocationHandler 类似 , 它只定义了一个方法 intercept(),用于增强目标方法

  1. Enhancer.create() : 用来生成一个代理对象

  • type : 被代理的类或者接口
  • callback : 自定义方法拦截器 Interceptor

2.AOP 底层原理 :

Spring AOP : 运行时生成动态代理 , 在代理里调用切面通知

如何选择代理 :

配置

目标对象

代理方式

proxyTargetClass=false

实现接口

JDK

proxyTargetClass=false

无接口

CGLIB

proxyTargetClass=true

任意

CGLIB

Spring Boot 2.x 以后默认全部使用 CGLIB

核心流程

  • 加载 Bean → 发现有 @Aspect 切面
  • 根据切点表达式匹配方法
  • 选择 JDK / CGLIB 创建代理对象
  • 方法调用 → 走代理 → 执行通知 → 执行目标方法

3.使用场景

  • 统一登录校验(可替代拦截器)
  • 接口日志记录
  • 方法执行耗时统计
  • 全局异常捕获
  • 统一返回值包装
  • 权限控制
  • 事务管理 @Transactional
  • 限流、缓存、幂等性

更多推荐