[Java EE 进阶] 深入理解 Spring AOP:从入门到原理,一篇彻底吃透(2)
·
SpringAOP 快速入门 :
三.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 动态代理(必须有接口)
实现步骤 :
- 定义一个接口及其实现类
- 自定义 InvocationHandler 并重写 invoke 方法 , 在 invoke 方法中我们会调用目标方法并自定义一些处理逻辑
- 通过 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)
);
}
}
解析 :
- InvocationHandler

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

- newProxyInstance() , 这个方法主要用来生成一个代理对象 ; 这个方法共有三个参数 :
- loder : 类加载器 , 用于加载代理对象
- interfaces : 被代理类实现的一下接口(意味着 JDK 动态代理只能代理已经实现了接口的一些类)
- h : 实现了 InvocationHandler 接口的对象
②CGLIB 动态代理(无接口也能代理)
Code Generation Library : 是一个基于 ASM 的字节码生成库 , 它允许我们在运行时对字节码进行修改和动态生成 ; 生成目标类的字类作为代理 ; 无需接口
实现步骤 :
- 定义一个类
- 自定义 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();
}
}
解析 :
- MethodInterceptor : 和 JDK 动态代理中的 InvocationHandler 类似 , 它只定义了一个方法 intercept(),用于增强目标方法

- 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
- 限流、缓存、幂等性
更多推荐



所有评论(0)