原理
May 8, 2024About 3 min
原理
Spring AOP(面向切面编程)是 Spring 框架提供的一个功能,用于在运行时动态地将通用的横切关注点(如日志记录、性能监控、事务管理等)插入到应用程序的代码中。
它可以将与业务无关的功能(例如日志、安全、事务等)从业务代码中分离出来,从而提高代码的可重用性和可维护性。
Spring AOP通过为目标对象生成一个代理对象,实现对目标对象的方法调用进行拦截和增强。
Spring AOP 的实现原理是基于动态代理和字节码操作的。
在编译时,Spring 会使用 AspectJ 编译器将切面代码编译成字节码文件。
在运行时,Spring 会根据切面配置使用JDK动态代理或CGLIB代理生成代理类,这些代理类会在目标对象方法执行前后插入切面代码,从而实现 AOP 的功能。
具体来说,Spring AOP 的实现原理可以分为以下几个步骤:
- 切面定义:使用 AspectJ 语法定义切面,包括切入点、通知方法等。
- 切面编译:使用 AspectJ 编译器将切面代码编译成字节码文件。
- 代理生成:Spring 会根据切面配置生成代理类,这些代理类会在目标对象方法执行前后插入切面代码。
- 目标对象替换:Spring 会将代理类替换为目标对象,从而使切面代码能够在目标对象方法执行前后执行。
Spring AOP 支持两种动态代理方式:JDK 动态代理和 CGLIB 动态代理。
- JDK 动态代理:JDK 动态代理是基于 Java 反射机制实现的,它只能对实现了接口的目标对象进行代理。
- CGLIB 动态代理:CGLIB是一个强大的字节码生成库,它能够在运行时动态生成类的子类,实现对目标对象的代理,包括没有实现接口的目标对象。
Spring AOP 默认使用 JDK 动态代理,若目标对象未实现接口,则用 CGLIB 动态代理。
JDK Proxy
缺点:对于未实现任何接口的类,无法进行代理。
Proxy.newProxyInstance
ReflectiveMethodInvocation
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
private final AdvisedSupport advised;
public JdkDynamicAopProxy(AdvisedSupport advised) {
this.advised = advised;
}
@Override
public Object getProxy() {
return Proxy.newProxyInstance(
getClass().getClassLoader(),
advised.getTargetSource().getInterfaces(),
this
);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInterceptor methodInterceptor = advised.getMethodInterceptor();
MethodInvocation methodInvocation = new ReflectiveMethodInvocation(
advised.getTargetSource().getTarget(),
method,
args,
methodInterceptor,
advised.getTargetSource().getTargetClass()
);
return methodInvocation.proceed();
}
}
CGLIB
原理:动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。
底层:使用字节码处理框架ASM,来转换字节码并生成新的类。
不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
缺点:对于final修饰的类和方法,无法进行代理。
核心用法:
Enhancer
setSuperclass
setCallback
CglibMethodInvocation
public class CglibAopProxy implements AopProxy {
private final AdvisedSupport advised;
public CglibAopProxy(AdvisedSupport advised) {
this.advised = advised;
}
@Override
public Object getProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(advised.getTargetSource().getTargetClass());
enhancer.setCallback(new DynamicAdvisedInterceptor(advised));
return enhancer.create();
}
private static class DynamicAdvisedInterceptor implements MethodInterceptor {
private final AdvisedSupport advised;
public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
MethodInvocation methodInvocation = new CglibMethodInvocation(
advised.getTargetSource().getTarget(),
method,
args,
proxy,
advised.getMethodInterceptor(),
advised.getTargetSource().getTargetClass()
);
return methodInvocation.proceed();
}
}
}