赞
踩
Java动态代理是如何实现的?JDK Proxy 和 CGLib 有什么区别?
本文深入探讨了Java动态代理的实现机制,分别介绍了使用JDK Proxy和CGLib两种不同方式来实现动态代理。
文章进一步对比了JDK Proxy与CGLib的主要区别,JDK Proxy主要依赖于java.lang.reflect.Proxy
类和java.lang.reflect.InvocationHandler
接口,它允许在运行时动态创建实现了一组接口的代理类实例,但仅限于代理那些已实现接口的类。相比之下,CGLib通过在运行时生成目标类的子类来实现代理,从而克服了JDK Proxy只能代理接口的限制。包括代理对象的类型、性能差异、使用场景以及依赖问题。尽管两者都可以实现动态代理,但选择哪一种方式取决于具体需求:如果目标对象已经实现了接口,则JDK Proxy是一个简单直接的选择;若需要代理没有实现接口的普通类,则CGLib是更合适的选择。
文中还探讨了Spring框架中动态代理的应用,Spring可以根据情况自动选择使用JDK Proxy或CGLib来实现代理,为开发者提供了更高层次的抽象和便利。同时,也简要介绍了Lombok库是如何利用代理原理来减少样板代码并提高开发效率的。
Java动态代理主要依赖于java.lang.reflect.Proxy
类和java.lang.reflect.InvocationHandler
接口来实现。其基本思想是,在运行时动态创建一个实现了一组接口的代理类的实例,然后将对该实例的所有方法调用转发给一个处理器(即实现了InvocationHandler接口的类的实例)。
Java动态代理是Java高级编程中的一项强大功能,它允许开发者在运行时创建代理实例来控制对其他对象的访问。这种技术广泛应用于AOP(面向切面编程)、RPC(远程过程调用)框架、事务管理等领域。本文旨在深入探讨Java动态代理的实现机制,并比较JDK Proxy和CGLib两种实现方式的异同。
动态代理的常用实现方式是反射。反射机制是指程序在运行期间可以访问、检测和修改其本身状态或行为的一种能力,使用反射我们可以调用任意一个类对象,以及类对象中包含的属性及方法。
动态代理可以通过 CGLib 来实现,而 CGLib 是基于 ASM(一个 Java 字节码操作框架)而非反射实现的。
简单来说,动态代理是一种行为方式,而反射或 ASM 只是它的一种实现手段而已。
JDK动态代理只能代理实现了接口的类。
InvocationHandler
接口,重写invoke
方法。在这里可以插入自定义的逻辑,比如日志记录、权限检查等。Proxy.newProxyInstance
方法,传入类加载器、接口数组以及InvocationHandler实例,来动态生成代理对象。- public interface Subject {
- void doSomething();
- }
-
- public class RealSubject implements Subject {
- @Override
- public void doSomething() {
- System.out.println("Doing something...");
- }
- }
-
- public 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 {
- // Before advice
- System.out.println("Before method call");
- Object result = method.invoke(target, args);
- // After advice
- System.out.println("After method call");
- return result;
- }
- }
-
- Subject subject = (Subject) Proxy.newProxyInstance(
- RealSubject.class.getClassLoader(),
- new Class[]{Subject.class},
- new MyInvocationHandler(new RealSubject())
- );
-
- subject.doSomething();
与JDK Proxy不同,CGLib能够代理未实现接口的类。它通过在运行时动态生成被代理类的子类,来拦截对父类方法的调用。
MethodInterceptor
接口,重写intercept
方法,在该方法中添加自定义逻辑。Enhancer
类,设置父类和回调,从而创建代理对象。- public class RealSubject {
- public void doSomething() {
- System.out.println("Doing something...");
- }
- }
-
- Enhancer enhancer = new Enhancer();
- enhancer.setSuperclass(RealSubject.class);
- enhancer.setCallback(new MethodInterceptor() {
- @Override
- public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
- // Before advice
- System.out.println("Before method call");
- Object result = proxy.invokeSuper(obj, args);
- // After advice
- System.out.println("After method call");
- return result;
- }
- });
-
-
- RealSubject subject = (RealSubject) enhancer.create();
- subject.doSomething();
尽管JDK Proxy和CGLib都可用于实现Java动态代理,但它们之间存在一些关键差异:
动态代理的常见使用场景有 RPC 框架的封装、AOP(面向切面编程)的实现、JDBC 的连接等。
Spring 框架中同时使用了两种动态代理 JDK Proxy 和 CGLib,当 Bean 实现了接口时,Spring 就会使用 JDK Proxy,在没有实现接口时就会使用 CGLib,我们也可以在配置中指定强制使用 CGLib,只需要在 Spring 配置中添加 <aop:aspectj-autoproxy proxy-target-class="true"/> 即可。
Lombok是一个工具类可以解决又重复的代码,如 Setter、Getter、toString、equals 和 hashCode 等等,向这种方法都可以使用 Lombok 注解来完成。 需要在 IDE 中安装 Lombok 插件,如下图所示:
Lombok 的实现和反射没有任何关系,Lombok 是在编译期就为我们生成了对应的字节码其实 Lombok 是基于 Java 1.6 实现的 JSR 269: Pluggable Annotation Processing API 来实现的,也就是通过编译期自定义注解处理器来实现的,它的执行步骤如下:
从流程图中可以看出,在编译期阶段,当 Java 源码被抽象成语法树(AST)之后,Lombok 会根据自己的注解处理器动态修改 AST,增加新的代码(节点),在这一切执行之后就生成了最终的字节码(.class)文件,这就是 Lombok 的执行原理。
Java动态代理是Java高级编程中的一个强大工具,它提供了一种灵活的方式来增强方法调用。通过对比JDK Proxy和CGLib,可以看出每种方法各有优势和适用场景。选择合适的动态代理实现方式,可以帮助开发者编写更加灵活和高效的代码。在实际开发中,根据具体需求选择最适合的代理方式,是提升项目质量和维护性的关键。
如果本文对你有帮助 欢迎 关注 、点赞 、收藏 、评论, 博主才有动力持续记录遇到的问题!!!
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/237659
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。