动态代理模式实现与对比(JDK、CGLIB、Spring AOP)

发布于:2025-03-29 ⋅ 阅读:(16) ⋅ 点赞:(0)

动态代理模式实现与对比


1. JDK动态代理(基于接口)

定义:通过 java.lang.reflect.ProxyInvocationHandler 实现代理,必须依赖接口
适用场景:目标对象实现接口,需动态增强方法。

代码示例
// 接口
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场景。

通过动态代理,可以灵活实现日志、事务、权限等横切逻辑,提升代码的可维护性和扩展性。