【Spring Boot】Spring AOP动态代理,以及静态
Spring AOP 动态代理与静态代理的区别
Spring AOP(面向切面编程)主要基于动态代理实现,而静态代理是另一种代理模式。以下是两者的核心区别和实现方式:
动态代理
动态代理在运行时动态生成代理类,无需手动编写代理类代码。Spring AOP 默认使用动态代理,具体分为两种实现方式:
1. JDK 动态代理
- 基于接口实现,要求目标类必须实现至少一个接口。
- 通过
java.lang.reflect.Proxy生成代理对象。 - 示例代码:
public interface UserService {void save(); }public class UserServiceImpl implements UserService {public void save() {System.out.println("保存用户");} }public class JdkProxyFactory {public static Object getProxy(Object target) {return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),(proxy, method, args) -> {System.out.println("前置增强");Object result = method.invoke(target, args);System.out.println("后置增强");return result;});} }
2. CGLIB 动态代理
- 基于继承实现,无需接口,通过字节码技术生成目标类的子类。
- 适用于未实现接口的类。
- 示例代码:
public class UserService {public void save() {System.out.println("保存用户");} }public class CglibProxyFactory implements MethodInterceptor {public Object getProxy(Class<?> clazz) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(clazz);enhancer.setCallback(this);return enhancer.create();}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 interface UserService {void save();
}public class UserServiceImpl implements UserService {public void save() {System.out.println("保存用户");}
}public class UserServiceProxy implements UserService {private UserService target;public UserServiceProxy(UserService target) {this.target = target;}public void save() {System.out.println("前置增强");target.save();System.out.println("后置增强");}
}
静态代理的局限性
- 代理类与目标类一一对应,代码冗余。
- 修改代理逻辑需修改所有代理类,维护成本高。
动态代理与静态代理的对比
| 特性 | 动态代理 | 静态代理 |
|---|---|---|
| 生成时机 | 运行时动态生成 | 编译时手动编写 |
| 灵活性 | 高(可动态适配不同类) | 低(需手动编写) |
| 性能 | 略低(反射开销) | 高(直接调用) |
| 适用场景 | Spring AOP、复杂逻辑 | 简单逻辑、固定代理需求 |
Spring AOP 的默认行为
- 若目标类实现了接口,默认使用 JDK 动态代理。
- 若目标类未实现接口,使用 CGLIB 动态代理。
- 可通过配置强制使用 CGLIB:
spring.aop.proxy-target-class=true
静态代理的适用场景
- 代理逻辑简单且固定。
- 需要极致性能(如高频调用场景)。
- 无法依赖动态代理库(如特殊环境限制)。
