003.Spring AOP的原理——Spring AOP简介——AOP的核心概念——AOP的2种代理方式——AOP的5种通知类型
1.6 Spring AOP原理
Spring AOP通过面向切面技术将与业务无关却为业务模块所共用的逻辑代码封装起来,以提高代码的复用率,降低模块之间的耦合度。
Spring AOP将引用分为核心关注点和横切关注点两个部分。业务处理流程为核心关注点,被业务说依赖的公共部分为横切关注点。横切关注点的特点是其行为经常发生在核心关注点的多处,而多处操作基本相似,比如权限认证、日志、事务。AOP的核心思想是将:核心关注点和横切关注点分离开来,以降低模块耦合度。Spring AOP的主要应用如下:
1.6.2 Spring AOP的2种代理模式
Spring 提供了JDK和CGLib2种方式来生成代理对象,具体生成代理对象的方式由AopProxyFactory根据AdvisedSupport对象的配置来决定。Spring默认的代理对象生成策略为:如果是目标类接口,则使用JDK动态代理技术,否则使用CGLib动态代理技术。
- JDK动态代理主要通过 java.lang.reflect 包中 Proxy 类和InvocationHandler接口来实现。InvocationHandler是一个接口,不同的实现类定义不同的横切逻辑,并通过反射机制调用目标类的代码,动态地将横切逻辑和业务逻辑编制在一起。Proxy 类利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。JDK 1.8中Proxy类的定义如下:
public class Proxy implements java.io.Serializable{
private static final long serialVersionUID = -2222568056686623797L;
// 1: 在构造方法参数中定义不同的InvocationHandler实现类
private static final Class<?>[] constructorParams = {
InvocationHandler.class};
//2:Proxy类缓存列表
private static final WeakCache<ClassLoader,Class<?>[],Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(),new ProxyClassFactory());
//3:当前代理需要调用的Handler实例对象(该对象需要经过序列化)
protected InvocationHandler h;
// ... ... 此处省略部分实现代码
//4.Proxy类构造函数,参数InvocationHandler为当前代理的对象
protected Proxy(InvocationHandler h){
Objects.requireNonNull(h);
this.h = h;
}
... ...
}
- CGLib动态代理:CGLib即Code Generation Library,它是一个高性能的代码生成类库,可以在运行期间扩展Java类和实现java接口。CGLib包的底层通过字节码处理框架ASM来实现,通过转换字节码生成新的类。
- CGLib动态代理和JDK动态代理的区别:JDK只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,则只能通过CGLib创建动态代理来实现。
1.6.4 AOP的5种通知类型
Spring AOP有5种通知类型,具体如下表所示:
1.6.5 AOP的代码实现
在Spring 中,AOP的使用比较简单,如下代码通过@Aspect注解声明一个切面,通过@Pointcut定义需要拦截的方法,然后用@Before、@AfterReturning、@Around、分别实现前置通知、后置通知和环绕通知的方法。
@Aspect // step 1: 定义切面
public class TransactionDemo{
//step 2:定义要拦截的方法
@Pointcut(value = "exception(* com.alex.core.service.*.*.*.(..))")
public void point(){
}
@Before(value = "point()") // step 3:定义前置通知
public void before(){
System.out.println("transaction begin");
}
@AfterReturning(value = "point()") // step 4:定义后置通知
public void after(){
System.out.println("transaction commit");
}
@Around("point()") // step 5:定义环绕通知
public void around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("transaction begin");
joinPoint.proceed();
System.out.println("transaction commit!);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构