动态代理模式实现与对比
1. JDK动态代理(基于接口)
定义:通过 java.lang.reflect.Proxy
和 InvocationHandler
实现代理,必须依赖接口。
适用场景:目标对象实现接口,需动态增强方法。
代码示例
// 接口
interface Service {
void execute();
}
// 目标对象
class RealService implements Service {
@Override
public void execute() {
System.out.println("Executing real service");
}
}
// 代理处理器(实现InvocationHandler)
class ServiceProxy implements InvocationHandler {
private Object target;
public ServiceProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before execution");
Object result = method.invoke(target, args);
System.out.println("After execution");
return result;
}
// 生成代理对象
public Object getProxy() {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this
);
}
}
// 使用示例
public class Main {
public static void main(String[] args) {
RealService realService = new RealService();
ServiceProxy proxy = new ServiceProxy(realService);
Service serviceProxy = (Service) proxy.getProxy();
serviceProxy.execute();
}
}
注释说明:
ServiceProxy
实现InvocationHandler
,通过invoke()
方法拦截目标方法。Proxy.newProxyInstance()
生成代理对象,必须传入接口列表。- 输出:
Before execution Executing real service After execution
2. CGLIB动态代理(基于继承)
定义:通过继承目标类实现代理,无需接口。
适用场景:目标对象未实现接口,需动态增强方法。
代码示例
// 目标类(无接口)
class RealService {
public void execute() {
System.out.println("Executing real service");
}
}
// 代理增强类(实现MethodInterceptor)
class ServiceInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before execution");
Object result = proxy.invokeSuper(obj, args); // 调用父类方法
System.out.println("After execution");
return result;
}
}
// 使用示例
public class Main {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealService.class);
enhancer.setCallback(new ServiceInterceptor());
RealService serviceProxy = (RealService) enhancer.create();
serviceProxy.execute();
}
}
注释说明:
Enhancer
创建代理对象,通过setSuperclass()
指定目标类。MethodInterceptor
实现intercept()
方法,通过invokeSuper()
调用原方法。- 输出:
Before execution Executing real service After execution
3. Spring AOP动态代理
定义:Spring整合JDK和CGLIB,自动选择代理方式。
适用场景:AOP编程,统一管理横切关注点(如日志、事务)。
代码示例
// 接口
interface Service {
void execute();
}
// 目标类
@Service
class RealService implements Service {
@Override
public void execute() {
System.out.println("Executing real service");
}
}
// 切面类(使用@Aspect)
@Aspect
@Component
class LoggingAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Before execution");
Object result = joinPoint.proceed();
System.out.println("After execution");
return result;
}
}
// 配置类
@Configuration
@EnableAspectJAutoProxy
class AppConfig {
@Bean
public RealService realService() {
return new RealService();
}
}
// 测试类
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
Service service = context.getBean(RealService.class);
service.execute();
}
}
注释说明:
- Spring自动选择JDK或CGLIB代理(有接口用JDK,无接口用CGLIB)。
@Aspect
和@Around
注解定义切面和环绕通知。- 输出与前两种代理一致。
对比表格
实现方式 | 原理 | 依赖接口 | 适用场景 | 性能 | 优缺点 |
---|---|---|---|---|---|
JDK动态代理 | 通过 Proxy 类生成代理类,继承 InvocationHandler 。 |
需要 | 目标对象实现接口的场景(如Spring AOP的接口服务)。 | 较高(接口调用开销小)。 | 实现简单,但无法代理无接口类。 |
CGLIB代理 | 通过生成目标类的子类,重写所有方法。 | 不需要 | 目标对象未实现接口的场景(如无接口的实体类)。 | 较低(反射生成子类,性能稍差)。 | 支持无接口类,但无法代理 final 方法或类。 |
Spring AOP | 自动选择JDK或CGLIB,通过注解简化代理配置。 | 自动判断 | 需要AOP统一管理日志、事务等横切关注点。 | 根据代理方式而定。 | 高度集成Spring,但需依赖框架。 |
关键区别
维度 | JDK动态代理 | CGLIB代理 |
---|---|---|
生成方式 | 通过 Proxy 类生成代理类,继承 InvocationHandler 。 |
通过字节码生成目标类的子类,重写所有非 final 方法。 |
性能 | 更快(接口调用直接通过反射)。 | 较慢(需生成子类,反射调用 MethodProxy )。 |
适用性 | 必须有接口。 | 无需接口,但无法代理 final 方法或类。 |
Spring集成 | 默认优先选择(当有接口时)。 | 当无接口时自动选择。 |
总结
- 选择JDK动态代理:目标对象实现接口,追求高性能。
- 选择CGLIB代理:目标对象无接口,或需增强
final
方法(Spring Boot默认启用)。 - Spring AOP:通过注解自动选择代理方式,推荐用于AOP场景。
通过动态代理,可以灵活实现日志、事务、权限等横切逻辑,提升代码的可维护性和扩展性。