Spring AOP 实现方式
Spring AOP(面向切面编程)主要有以下几种实现方式:
1. 基于代理的 AOP 实现
- JDK 动态代理:
- 原理:JDK 动态代理是基于接口的代理方式。它利用 Java 的反射机制,在运行时创建一个实现了目标对象所实现接口的代理对象。代理对象会拦截对目标对象方法的调用,并在调用前后执行额外的增强逻辑。
- 使用场景:适用于目标对象实现了接口的情况。
- 示例代码:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 接口
interface UserService {
void addUser();
}
// 目标对象
class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("添加用户");
}
}
// 调用处理器
class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(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 JdkProxyExample {
public static void main(String[] args) {
UserService target = new UserServiceImpl();
MyInvocationHandler handler = new MyInvocationHandler(target);
UserService proxy = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler
);
proxy.addUser();
}
}
- CGLIB 代理:
- 原理:CGLIB(Code Generation Library)是一个强大的、高性能的代码生成库。CGLIB 代理通过继承目标对象类,在运行时生成一个子类作为代理对象。它会重写目标对象的方法,在方法调用前后插入增强逻辑。
- 使用场景:适用于目标对象没有实现接口的情况。
- 示例代码:
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
// 目标对象
class UserService {
public void addUser() {
System.out.println("添加用户");
}
}
// 方法拦截器
class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("方法调用前");
Object result = proxy.invokeSuper(obj, args);
System.out.println("方法调用后");
return result;
}
}
public class CglibProxyExample {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
enhancer.setCallback(new MyMethodInterceptor());
UserService proxy = (UserService) enhancer.create();
proxy.addUser();
}
}
2. 基于 AspectJ 的 AOP 实现
- 原理:AspectJ 是一个功能强大的 AOP 框架,Spring AOP 集成了 AspectJ 的部分功能。它可以通过注解或 XML 配置来定义切面、切点和增强逻辑。与基于代理的 AOP 不同,AspectJ 可以在编译时、类加载时或运行时织入增强逻辑。
- 使用场景:当需要更复杂的切面定义和更细粒度的织入控制时使用。
- 示例代码(注解方式):
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
// 切面类
@Aspect
@Component
public class LoggingAspect {
// 定义切点
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceMethods() {}
// 前置增强
@Before("serviceMethods()")
public void beforeAdvice() {
System.out.println("方法调用前");
}
// 后置增强
@After("serviceMethods()")
public void afterAdvice() {
System.out.println("方法调用后");
}
}
动态代理(JDK 动态代理)和 CGLIB 代理的区别
1. 代理机制
- JDK 动态代理:基于接口实现,代理对象实现了目标对象所实现的接口,通过反射调用目标对象的方法。
- CGLIB 代理:基于继承实现,代理对象是目标对象的子类,通过重写目标对象的方法来实现增强逻辑。
2. 适用场景
- JDK 动态代理:要求目标对象必须实现接口,只能代理接口中定义的方法。
- CGLIB 代理:不要求目标对象实现接口,可以代理普通类的方法。但如果目标对象的方法是
final
或static
的,CGLIB 无法对其进行代理。
3. 性能
- JDK 动态代理:在创建代理对象时,由于使用反射机制,性能相对较低。但在方法调用时,性能较好。
- CGLIB 代理:在创建代理对象时,由于需要生成子类字节码,性能相对较高。但在方法调用时,由于需要通过方法代理调用父类方法,性能相对较低。
4. 代码复杂度
- JDK 动态代理:代码相对简单,只需要实现
InvocationHandler
接口即可。 - CGLIB 代理:代码相对复杂,需要引入 CGLIB 库,并实现
MethodInterceptor
接口。