当前位置: 首页 > news >正文

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

动态代理模式实现与对比


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场景。

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

相关文章:

  • vue数据两个相同的参数对比只显示一个
  • HarmonyOS主题管理工具封装:动态切换、持久化存储与常见问题解析
  • sourcetree中的“master“,“origin/master“,“origin/HEAD“这三个图标都是什么意思?GIT 超详细➕通俗易懂版本
  • Unity中对象池(Object Pool)技术解析与实现
  • 【聚合函数、分组、排序笔记】
  • SSE单向消息推送(get请求)
  • 神经网络 - 前馈神经网络(FNN)、全连接神经网络(FCNN)和卷积神经网络(CNN)的区别与联系
  • MySQL的多表查询
  • 软考《信息系统运行管理员》- 6.1 信息系统安全概述
  • Oracle数据库数据编程SQL<2.2 DDL 视图、序列>
  • lxd-dashboard 图形管理LXD/LXC
  • Processor System Reset IP 核 v5.0(vivado)
  • Allegro界面颜色改变设置
  • Qt应用系统托盘区域显示、托盘菜单示例
  • 快速排序不啦不啦
  • 嵌入式Linux网络编程:UNIX Domain Socket进程间通信(IPC)
  • Maven版本统一管理
  • 如何在Webpack中配置别名路径?
  • Google开源机器学习框架TensorFlow探索更多ViT优化
  • Ubuntu 系统无法远程连接?完整排查指南与解决方案
  • 水豚“豆包”出逃已40天,扬州茱萸湾景区追加悬赏
  • 金俊峰已跨区任上海金山区委副书记
  • 贵州省总工会党组成员、副主席梁伟接受审查调查
  • 西安机场回应航站楼“水帘洞”事件:屋面排水系统被冰雹堵塞
  • 构建菌株有效降解有机污染物,上海交大科研成果登上《自然》
  • 古埃及展进入百天倒计时,闭幕前168小时不闭馆