在此前的IoC、Web、数据访问等各模块设计中我们多多少少提到了Spring AOP,说是让码友把它当成一个“黑盒”;而此刻就是我们要把这个“黑盒”打开了。
Spring AOP是Spring框架提供的面向切面编程(AOP)实现,通过动态代理技术将横切关注点(如日志、事务、安全)模块化为切面,并在不修改业务代码的前提下,通过切点匹配和通知机制将切面逻辑织入到目标方法中,实现业务逻辑与横切逻辑的解耦。
在传统的面向对象编程(OOP)中,开发人员面临以下挑战:
示例(无AOP):
public class UserService {
public void createUser(User user) {
// 1. 日志记录(横切逻辑)
System.out.println("调用createUser方法");
// 2. 核心业务逻辑
// ...
// 3. 事务管理(横切逻辑)
try {
// ...
} catch (Exception e) {
// 回滚事务
}
}
}
上述代码中,日志和事务管理逻辑与业务逻辑混杂,导致代码臃肿且难以维护。
基于以上示例,聪明的码友们应该已经迫不及待要搞一个工具出来解决这个问题了,首先要能解决这几个问题:
@Aspect
)定义切面行为外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
组件 | 职责 | 关键技术 |
---|---|---|
切入点(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
封装调用上下文ProxyFactory
动态生成代理对象。@Before
→ 目标方法
→ @After
→ @AfterReturning
/@AfterThrowing
。@Around
通知覆盖整个流程,需显式调用 proceed()
。@AfterThrowing
)仅在方法抛出异常时触发。java.lang.reflect.Proxy
生成代理类。 org.springframework.aop.framework.JdkDynamicAopProxyspring.aop.proxy-target-class=true
)。Pointcut
和 Advice
的组合,通过策略模式动态选择通知逻辑。ProxyFactory
或 ProxyFactoryBean
创建代理对象。AdvisorAdapter
将不同类型的Advice
(通知)适配为统一的 MethodInterceptor
接口,以便动态代理统一调用。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();
}
}
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()
);
}
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();
}
public interface IsModified {
boolean isModified();
}
public class IsModifiedMixin implements IsModified, IntroductionAdvisor {
// 实现混入逻辑
}
// 应用引入
proxyFactory.addAdvisor(new IsModifiedMixin());
@Bean
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public PrototypeBean prototypeBean() {
return new PrototypeBean();
}
public class RoutingDataSourceProxy implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) {
if (isReadOperation(invocation.getMethod())) {
return readDataSource.invoke(invocation);
}
return writeDataSource.invoke(invocation);
}
}
@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);
}
});
}
}
@EnableAspectJAutoProxy
一键启用@Order
控制增强执行顺序终极价值:让开发者通过声明式方式实现横切关注点,保持业务代码的纯净性和可维护性,同时提供强大的扩展能力满足复杂场景需求。