在此前的IoC、Web、数据访问等各模块设计中我们多多少少提到了Spring AOP,说是让码友把它当成一个"黑盒";而此刻就是我们要把这个"黑盒"打开了。
Spring AOP是Spring框架提供的面向切面编程(AOP)实现,通过动态代理技术将横切关注点(如日志、事务、安全)模块化为切面,并在不修改业务代码的前提下,通过切点匹配和通知机制将切面逻辑织入到目标方法中,实现业务逻辑与横切逻辑的解耦。
一、背景及设计理念
1、痛点问题
在传统的面向对象编程(OOP)中,开发人员面临以下挑战:
- 代码冗余:日志记录、事务管理、权限校验等横切关注点需要分散到每个业务方法中,导致代码重复。
- 耦合度高:业务逻辑与横切逻辑紧密耦合,难以独立维护或复用。
- 扩展性差:新增横切功能(如性能监控)需修改所有相关业务代码,违反开闭原则。
示例(无AOP):
java
public class UserService {
public void createUser(User user) {
// 1. 日志记录(横切逻辑)
System.out.println("调用createUser方法");
// 2. 核心业务逻辑
// ...
// 3. 事务管理(横切逻辑)
try {
// ...
} catch (Exception e) {
// 回滚事务
}
}
}
上述代码中,日志和事务管理逻辑与业务逻辑混杂,导致代码臃肿且难以维护。
2、解决方案
基于以上示例,聪明的码友们应该已经迫不及待要搞一个工具出来解决这个问题了,首先要能解决这几个问题:
1. 关注点分离
- 核心思想:将横切关注点(如日志、事务、安全)与核心业务逻辑解耦
- 实现方式:通过代理机制将横切逻辑动态织入目标对象
2. 非侵入式设计
- 零污染:目标对象无需实现特定接口或继承特定类
- 透明代理:调用方无感知地使用代理对象替代原始对象
3. 灵活的织入模型
- 多种织入时机:编译时、类加载时、运行时
- 多种织入方式:接口代理、子类代理、字节码增强
4. 声明式编程范式
- 元数据驱动 :通过注解(如
@Aspect
)定义切面行为 - 约定优于配置:合理的默认配置,特殊需求可定制
5. 模块化扩展
- 可插拔增强:前置、后置、环绕、异常等增强类型
- 开放扩展点:自定义切入点、增强逻辑、代理策略
二、核心组件与职能划分
模块关系图

组件职能划分
组件 | 职责 | 关键技术 |
---|---|---|
切入点(Pointcut) | 定义"在哪里增强"(如匹配UserService 的所有delete* 方法);定义匹配目标方法的规则(如包路径、方法名、参数类型),决定通知的应用范围 |
表达式解析(ANTLR) |
增强(Advice) | 定义"增强什么逻辑"(如日志方法log()) | 动态字节码(ASM/CGLIB) |
切面(Aspect) | 组合Pointcut+Advice (如"在删除方法前记录日志") |
注解解析(@Aspect ) |
代理工厂(ProxyFactory) | 将Aspect织入目标Bean,生成代理对象 | JDK动态代理/CGLIB |
执行链(Chain) | 当代理方法被调用时,按顺序执行多个Advice(如先权限校验→再事务开启)责任链模式 | 责任链模式 |
目标对象(Target Object) | 需要被增强的原始对象(业务逻辑的实现类)。 | |
代理对象(Proxy) | 通过动态代理生成的对象,封装了目标对象和切面逻辑。 |
代理执行流程
AOP最重要的就是代理执行,代理包含:JDK动态代理或CGLib动态代理

设计亮点:
- 递归执行:通过
MethodInvocation.proceed()
实现链式调用 - 上下文传递:
MethodInvocation
封装调用上下文 - 异常处理:统一拦截异常增强执行点
关键设计细节
- 代理对象生成时机 :在Spring IoC容器初始化时,通过
ProxyFactory
动态生成代理对象。 - 通知执行顺序 :
@Before
→目标方法
→@After
→@AfterReturning
/@AfterThrowing
。@Around
通知覆盖整个流程,需显式调用proceed()
。
- 异常处理 :异常通知(
@AfterThrowing
)仅在方法抛出异常时触发。 - 织入时机 :Spring AOP在运行时通过动态代理实现织入,无需编译期修改字节码。
三、关键设计模式应用
代理模式(Proxy Pattern)
- 实现方式 :
- JDK动态代理 :适用于目标对象实现接口的情况,通过
java.lang.reflect.Proxy
生成代理类。 org.springframework.aop.framework.JdkDynamicAopProxy - CGLIB代理:适用于无接口的目标对象,通过字节码生成技术动态创建子类。
- JDK动态代理 :适用于目标对象实现接口的情况,通过
- 选择策略 :
- 若目标对象有接口,Spring默认使用JDK动态代理;否则使用CGLIB。
- 可通过配置强制使用CGLIB(
spring.aop.proxy-target-class=true
)。
策略模式(Strategy Pattern)
- 应用场景 :
- Advisor :封装
Pointcut
和Advice
的组合,通过策略模式动态选择通知逻辑。 - AdvisorChainFactory:根据切入点匹配规则,决定通知链的执行顺序。
- Advisor :封装
工厂模式(Factory Pattern)
- 核心组件 :
- ProxyFactory :通过
ProxyFactory
或ProxyFactoryBean
创建代理对象。 - BeanFactoryPostProcessor:在IoC容器初始化时动态注册切面Bean。
- ProxyFactory :通过
责任链模式**(Chain of Responsibility Pattern)**
- 核心作用:解耦通知逻辑,支持动态扩展拦截器。
- 应用场景 :拦截器链(Interceptor Chain) 由多个 MethodInterceptor 组成,每个拦截器按顺序处理方法调用。以下是其核心流程:
- 动态代理生成:Spring 通过 ProxyFactory 创建代理对象,代理对象持有拦截器链。
- 拦截器链执行:代理对象调用 MethodInterceptor 的 invoke 方法,逐个执行拦截器逻辑。
- 通知类型划分:每个拦截器对应一种通知类型(如 @Before、@Around、@After),形成链式调用。
适配器模式**(Adapter Pattern)**
- 核心作用:统一接口,支持多种通知类型(前置、后置、异常等)。
- 应用场景 :Spring AOP 通过
AdvisorAdapter
将不同类型的Advice
(通知)适配为统一的MethodInterceptor
接口,以便动态代理统一调用。
四、扩展机制设计
1. 自定义增强类型
java
public interface CustomAdvice extends Advice {
void customBehavior(JoinPoint joinPoint);
}
public class CustomAdviceInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
// 自定义前置逻辑
customBehavior(new MethodInvocationProceedingJoinPoint(invocation));
return invocation.proceed();
}
}
2. 自定义切入点
java
public class CustomPointcut implements Pointcut {
private final ClassFilter classFilter;
private final MethodMatcher methodMatcher;
// 实现自定义匹配逻辑
public boolean matches(Method method, Class<?> targetClass) {
return method.isAnnotationPresent(CustomAnnotation.class);
}
}
// 注册自定义切入点
@Bean
public Advisor customAdvisor() {
return new DefaultPointcutAdvisor(
new CustomPointcut(),
new CustomAdviceInterceptor()
);
}
3. 自定义代理策略
java
public class CustomProxyCreator implements AopProxyFactory {
@Override
public AopProxy createAopProxy(AdvisedSupport config) {
if (config.isOptimize() || config.isProxyTargetClass()) {
return new CustomCglibProxy(config);
}
return new CustomJdkProxy(config);
}
}
// 配置自定义代理工厂
@Bean
public DefaultAopProxyFactory aopProxyFactory() {
return new CustomProxyCreator();
}
五、高级特性设计理念
1. 引入(Introduction)机制
- 概念:动态为对象实现新接口
- 实现原理:
java
public interface IsModified {
boolean isModified();
}
public class IsModifiedMixin implements IsModified, IntroductionAdvisor {
// 实现混入逻辑
}
// 应用引入
proxyFactory.addAdvisor(new IsModifiedMixin());
2. 作用域代理
- 解决问题:单例Bean引用原型Bean
- 实现方式:
java
@Bean
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public PrototypeBean prototypeBean() {
return new PrototypeBean();
}
3. 负载感知代理
- 动态策略:根据运行时条件选择不同实现
java
public class RoutingDataSourceProxy implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) {
if (isReadOperation(invocation.getMethod())) {
return readDataSource.invoke(invocation);
}
return writeDataSource.invoke(invocation);
}
}
4. 异步切面
java
@Aspect
public class AsyncExecutionAspect {
@Around("@annotation(async)")
public Object asyncExecution(ProceedingJoinPoint pjp, Async async) {
return CompletableFuture.supplyAsync(() -> {
try {
return pjp.proceed();
} catch (Throwable ex) {
throw new CompletionException(ex);
}
});
}
}
六、设计哲学总结
1. 分层抽象
- 代理层:封装代理创建机制
- 连接点模型:统一方法调用、字段访问等切点
- 增强抽象:定义横切逻辑执行方式
2. 扩展开放
- 代理策略:可替换JDK/CGLIB实现
- 切入点模型:支持自定义匹配逻辑
- 增强类型:可扩展新的增强类型
3. 性能优化
- 链式缓存:优化拦截器链执行
- 代理复用:避免重复创建代理
- 延迟初始化:按需创建代理对象
4. 容器集成
- Bean生命周期:在Bean初始化后创建代理
- 注解驱动 :
@EnableAspectJAutoProxy
一键启用 - 优先级管理 :
@Order
控制增强执行顺序
终极价值:让开发者通过声明式方式实现横切关注点,保持业务代码的纯净性和可维护性,同时提供强大的扩展能力满足复杂场景需求。