代理模式以及静态代理、JDK代理、Cglib代理的实现

这篇具有很好参考价值的文章主要介绍了代理模式以及静态代理、JDK代理、Cglib代理的实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

代理模式(Proxy)

介绍

1、代理模式:为对象提供一个替身,以控制对这个对象的访问,即通过代理对象访问目标对象,这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作

(即:扩展目标对象的功能,例如Spring AOP)

2、被代理的对象可以是远程对象,创建开销大的对象或需要安全控制的对象

3、代理模式有不同的形式,主要有三种:

  • 静态代理(也是一种基于接口的代理)

  • 动态代理(JDK代理/接口代理)

  • Cglib代理(在内存中动态创建对象,而不需要实现接口,属于动态代理的范畴)

这里是代理的示意图:

代理模式以及静态代理、JDK代理、Cglib代理的实现,代理模式,java,开发语言

静态代理

静态代理在使用时,需要定义接口或父类,被代理对象(即目标对象)与代理对象一起实现相同的接口或者是继承相同的接口

代理对象与目标对象实现相同的接口,通过调用相同的方法来调用目标对象方法。

代码示例

// 定义接口
interface Subject {
    void doAction();
}
​
// 目标对象
class RealSubject implements Subject {
    @Override
    public void doAction() {
        System.out.println("RealSubject is doing action");
    }
}
​
// 代理对象
class ProxySubject implements Subject {
//这里聚合一个RealSubject对象
    private RealSubject realSubject;
​
    public ProxySubject(RealSubject realSubject) {
        this.realSubject = realSubject;
    }
​
    @Override
    public void doAction() {
        System.out.println("ProxySubject is doing something before action");
        realSubject.doAction();
        System.out.println("ProxySubject is doing something after action");
    }
}
​
// 测试类
public class StaticProxyExample {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        ProxySubject proxySubject = new ProxySubject(realSubject);
​
        // 通过代理对象调用目标对象的方法
        proxySubject.doAction();
    }
}

代理模式以及静态代理、JDK代理、Cglib代理的实现,代理模式,java,开发语言

小结

优点:

  1. 易于理解和实现: 静态代理模式相对简单,易于理解和实现,适用于一些简单的代理场景。

  2. 对目标对象进行控制: 通过代理可以对目标对象的访问进行控制和管理,例如在调用目标对象方法前后进行额外的处理。

  3. 实现业务功能的解耦: 代理对象可以在不修改目标对象的情况下,增加额外的功能,实现了业务功能的解耦,提高了系统的可维护性。

  4. 保护目标对象: 代理对象可以充当一个保护层,控制用户对目标对象的访问权限,增加系统的安全性。

缺点:

  1. 静态: 静态代理在编译时就已经确定了代理类和目标类,如果需要代理多个类或者频繁地更换代理对象,会导致代码量增加,不利于系统的扩展和维护。

  2. 灵活性差: 静态代理模式的灵活性较低,一旦接口或者目标对象发生变化,代理类也需要相应地修改,不够灵活。

  3. 代码重复: 如果有多个接口或者多个目标对象需要被代理,会导致代理类的重复设计和编码,增加了开发工作量。

  4. 只能代理固定的目标对象: 静态代理模式在编译时就已经确定了代理类和目标类的关系,无法动态地切换或者增加新的代理对象。

总的来说,静态代理模式在一些简单的场景下是适用的,但在面对复杂的系统、多样的需求和频繁变化的代理对象时,可能会显得不够灵活和可扩展。在这种情况下,可以考虑使用动态代理模式或者其他结构型模式来实现更灵活、可扩展的代理功能。

动态代理

介绍

1、代理对象不需要实现接口,但是目标对象要实现接口,否则不能用动态代理

2、代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象

3、动态代理又称:JDK代理,接口代理

JDK中生成代理对象的API

1、代理类所在包:java.lang.reflect.Proxy

2、JDK实现代理只需要使用newProxyInstance方法,但是该方法需要接收3个参数,完整写法是:

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

代码示例

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
​
// 定义接口
interface Subject {
    void doAction();
}
​
// 目标对象
class RealSubject implements Subject {
    @Override
    public void doAction() {
        System.out.println("目标对象正在执行");
    }
}
​
// InvocationHandler 实现类
class ProxyHandler implements InvocationHandler {
    private Object target;
​
    public ProxyHandler(Object target) {
        this.target = target;
    }
​
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("目标对象执行前。。。");
        Object result = method.invoke(target, args);
        System.out.println("目标对象执行后。。。");
        return result;
    }
}
​
// 测试类
public class DynamicProxyExample {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
​
        // 创建动态代理对象
        //newProxySubject的三个参数:
        //1、ClassLoader:指定当前目标对象使用的类加载器,获取加载器的方法固定
        //2、Class<?>[] interfaces:目标对象实现的接口类型,使用泛型方法确定类型
        //3、InvocationHandler h:事情处理。执行目标对象方法时,会触发事情处理方法,会把当前执行的目标对象方法作为参数
        Subject proxySubject = (Subject) Proxy.newProxyInstance(
                Subject.class.getClassLoader(),
                new Class[]{Subject.class},
                new ProxyHandler(realSubject));
​
        // 通过代理对象调用目标对象的方法
        proxySubject.doAction();
    }
}
​

代理模式以及静态代理、JDK代理、Cglib代理的实现,代理模式,java,开发语言

小结

优点:

  1. 灵活性: 动态代理模式相比静态代理模式更加灵活,可以在运行时动态地创建代理对象,无需提前知道目标对象的具体类型。

  2. 减少代码量: 动态代理可以通过反射机制自动生成代理类,减少了手动编写代理类的代码量。

  3. 适应性强: 动态代理模式适用于多个目标类共享一个代理类或者频繁切换代理对象的场景。

  4. 可扩展性: 动态代理模式可以通过自定义 InvocationHandler 的实现类,实现对目标对象方法的统一处理,并且可以根据需求灵活地扩展功能。

缺点:

  1. 性能影响: 动态代理在运行时通过反射机制调用目标对象的方法,相比直接调用目标对象的方法,性能上会有一定的影响。

  2. 复杂性增加: 动态代理模式相对静态代理模式来说,涉及到更多的类和概念,代码结构可能会变得更加复杂,不利于代码的理解和维护。

  3. 无法代理私有方法: 动态代理无法直接代理目标对象中的私有方法,只能代理公共方法。

动态代理模式在一些需要灵活性和可扩展性的场景下非常有用。它可以减少代码量、提高代码的可复用性,并且可以在运行时动态地创建代理对象。然而,它也存在一些性能影响和复杂性增加的问题,需要根据具体情况权衡使用。

Cglib代理

介绍

1、静态代理和JDK代理都要求目标对象实现一个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候可使用目标对象子类来实现代理——Cglib代理

2、Cglib代理也叫做子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能扩展,有些地方也将Cglib代理归属动态代理

3、Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。

4、Cglib代理广泛使用在AOP框架中,例如Spring AOP,实现方法拦截。

在AOP编程中,如何选择代理模式呢?

  • 目标对象需要实现接口——JDK代理

  • 目标对象不需要实现接口——Cglib代理

5、Cglib包底层是通过使用字节码处理框架ASM来转换字节码并生成新的类

实现步骤

  1. 引入cglib的jar文件

     <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.4.1</version>
        </dependency>
  2. 因为在内存中动态构建子类,代理类不能是final,否则会报错

  3. 目标对象的方法如果是final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法。

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
​
import java.lang.reflect.Method;
​
/**
 * cglib代理测试
 */
​
class HelloWorld {
​
    public void sayHello() {
        System.out.println("CGLIB动态代理模式!");
    }
​
}
class CGLIBExampleProxy implements MethodInterceptor {
​
    /**
     * 指定cglib代理模式的代理类
     */
​
    private Object target;
​
    public Object bind(Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();
        //设置超类方法
        enhancer.setSuperclass(this.target.getClass());
        //设置一个回调方法,用来设置哪个类为代理类,this表示当前类为代理类
        enhancer.setCallback(this);
        //创建代理对象
        return enhancer.create();
​
    }
​
    //重写接口中的intercept方法,增强并执行代理方法
    public Object intercept(Object obj,
                            Method method, Object[] args,
                            MethodProxy proxy) throws Throwable {
        System.out.println("CGLIB代理前");
        Object object = proxy.invokeSuper(obj, args);
        System.out.println("CGLIB代理后");
        return object;
    }
}
public class CglibProxy {
    public static void main(String[] args) {
        //1.获取代理对象
        CGLIBExampleProxy proxy=new CGLIBExampleProxy();
        //2.获取代理对象
        HelloWorld hello=(HelloWorld)proxy.bind(new HelloWorld());
        //3.执行代理方法
        hello.sayHello();
    }
}

代理模式以及静态代理、JDK代理、Cglib代理的实现,代理模式,java,开发语言

如果报错

原因:
因为在使用 CGLIB 进行代理时,出现了对 Java 9+ 模块系统的限制导致的异常。在 Java 9+ 中,模块系统对于反射和类加载引入了更严格的访问控制。
​
解决:
尝试通过添加以下 JVM 参数来打开 java.base 模块的反射权限:
--add-opens java.base/java.lang=ALL-UNNAMED

代理模式以及静态代理、JDK代理、Cglib代理的实现,代理模式,java,开发语言

代理模式以及静态代理、JDK代理、Cglib代理的实现,代理模式,java,开发语言

代理模式以及静态代理、JDK代理、Cglib代理的实现,代理模式,java,开发语言

代理模式以及静态代理、JDK代理、Cglib代理的实现,代理模式,java,开发语言

代理模式以及静态代理、JDK代理、Cglib代理的实现,代理模式,java,开发语言

小结

优点:

  1. 不需要接口: CGLib 动态代理不要求目标对象实现接口,可以直接代理目标类的方法,这样就避免了 JDK 动态代理必须基于接口的限制。

  2. 性能高: CGLib 动态代理是通过生成目标类的子类来实现代理,因此在调用目标方法时比 JDK 动态代理更快,无需通过反射调用。

  3. 灵活性: CGLib 可以代理非公共的类,包括 final 类。同时,CGLib 也支持对类中的 final 方法进行代理。

  4. 功能丰富: CGLib 提供了丰富的 API,可以在代理过程中实现更复杂的逻辑,满足更多场景的需求。

缺点:

  1. 引入依赖: 使用 CGLib 动态代理需要引入额外的库,增加了项目的依赖性,可能会对项目构建和部署造成一定影响。

  2. 类加载器: 由于 CGLib 是通过生成目标类的子类来实现代理,因此需要使用字节码技术,在某些情况下可能会导致类加载问题或者冲突。

  3. 无法代理静态方法: CGLib 无法代理目标对象中的静态方法,因为动态代理实际上是通过生成目标对象的子类来实现代理,而静态方法是属于类级别的而不是实例级别的。

  4. 内存占用: 由于 CGLib 动态代理是通过生成子类来实现代理,可能会占用更多的内存,特别是在代理大量对象时可能会影响系统性能。

总的来说,CGLib 动态代理适合对类进行代理,无需目标对象实现接口的情况下使用。它具有高性能、灵活性强等优点,但也存在一些缺点,如引入依赖、无法代理静态方法等。在选择动态代理方式时,需要根据具体需求和场景来权衡选择适合的代理方式。

几种常见的代理模式介绍——几种变体

1、防火墙代理

内网通过代理穿透防火墙,实现对公网的访问

2、缓存代理

比如:当请求图片文件等资源时,先到缓存代理取,如果取不到,就到公网或数据库中取

3、远程代理 把远程对象当本地对象来调用。远程代理通过网络和真正的远程对象沟通信息

4、同步代理

用于多线程编程中,完成多线程间同步工作。

通过一个代理的服务器去访问真正提供服务的。

代理模式总结

本人理解:通过一个代理对象访问并增强另一个对象的功能。

代理模式是一种结构型设计模式,其目的是通过引入一个代理对象来控制对另一个对象的访问。代理对象可以在不改变原始对象的情况下,对其进行一些额外的操作,如控制对原始对象的访问权限、延迟加载、缓存数据、记录日志等。

角色

  • 抽象主题(Subject):定义了代理对象和真实对象的共同接口,客户端可以通过该接口访问真实对象。

  • 真实主题(Real Subject):实际执行业务逻辑的对象。

  • 代理(Proxy):包含了对真实主题的引用,并提供与真实主题相同的接口,负责控制对真实主题的访问。

优势

  • 代理对象可以拦截对真实对象的访问,可以在调用真实对象之前或之后执行一些额外的逻辑。

  • 可以实现延迟加载:代理对象可以延迟创建或加载真实对象,从而提高系统性能和节省资源。

  • 实现访问控制:代理对象可以控制对真实对象的访问权限,实现安全性控制。

  • 实现缓存:代理对象可以缓存真实对象的结果,避免重复计算或获取数据。

缺点

  • 增加系统复杂度

  • 性能损耗

  • 可能引入单点故障

  • 可能导致循环依赖

应用场景

  • 远程代理:控制访问远程对象。

  • 虚拟代理:控制访问创建开销大的对象。

  • 缓存代理:为耗时的操作结果提供缓存。

  • 保护代理:控制对敏感对象的访问权限。

  • 智能引用:在访问对象时执行额外操作,如引用计数。

代理模式能够增加代码的灵活性和可维护性,同时提供了一种优雅的方式来控制对象的访问和行为。通过合理地使用代理模式,可以更好地实现代码解耦和功能扩展。文章来源地址https://www.toymoban.com/news/detail-838723.html

到了这里,关于代理模式以及静态代理、JDK代理、Cglib代理的实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 3_代理模式(动态代理JDK原生和CGLib)

    1.概念 代理模式(Proxy Pattern )是指 为其他对象提供一种代理,以控制对这个对象的访问 ,属于结构型模式。 在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。 使用代理模式主要有两个目的: 一是保护目标

    2024年01月17日
    浏览(26)
  • 【面试精讲】Java动态代理是如何实现的?JDK Proxy 和 CGLib 有什么区别?

    Java动态代理是如何实现的?JDK Proxy 和 CGLib 有什么区别? 一、Java动态代理的实现 1、使用JDK Proxy实现动态代理 2、使用CGLib实现动态代理 二、JDK Proxy 与 CGLib 的区别 三、Spring中的动态代理 四、 Lombok代理原理 总结 本文深入探讨了Java动态代理的实现机制,分别介绍了使用JDK

    2024年03月14日
    浏览(34)
  • Spring之CGLIB和JDK动态代理底层实现

    目录 CGLIB 使用示例-支持创建代理对象,执行代理逻辑 使用示例-多个方法,走不同的代理逻辑 JDK动态代理 使用示例-支持创建代理对象,执行代理逻辑 ProxyFactory 如何自动在CGLIB和JDK动态代理转换 使用示例-使用CGLIB代理方式 使用示例-使用JDK动态代理方式 Spring会自动在JDK动态

    2024年04月25日
    浏览(19)
  • JDK动态代理和CGLIB动态代理

    JDK动态代理和CGLIB动态代理 ① JDK动态代理只提供接口的代理,不支持类的代理,要求被代理类实现接口。JDK动态代理的核心是InvocationHandler接口和Proxy类,在获取代理对象时,使用Proxy类来动态创建目标类的代理类(即最终真正的代理类,这个类继承自Proxy并实现了我们定义的

    2024年02月07日
    浏览(31)
  • 温故知新之:代理模式,静态代理和动态代理(JDK动态代理)

    代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。 静态代理 是一种代理模式的实现方式,它在编译期间就已经确定了代理对象,需要为每一个被代理对象创建一个代理类。静态代理的实现比较简单,但是每个被代理对象都需要创建

    2024年02月11日
    浏览(37)
  • SpringAOP-说说 JDK动态代理和 CGLIB 代理

    Spring 的 AOP 是通过动态代理来实现的,动态代理主要有两种方式 JDK 动态代理和 Cglib 动态代理,这两种动态代理的使用和原理有些不同。 JDK 动态代理 Interface :JDK动态代理是基于接口的代理,它要求目标类实现一个接口。 InvocationHandler :InvocationHandler 是一个接口,可以通过

    2024年01月18日
    浏览(34)
  • 【动态代理】JDK动态代理与cglib动态代理源码解析

    UserService ,接口类 UserServiceImpl ,实现类 使用代理,测试效果。 控制台输出: Proxy#newProxyInstance ,生成代理类的实例。 核心在于 getProxyClass0 ,生成代理类的类信息 使用自定义的InvocationHandler作为参数,调用构造函数获取代理类对象实例 WeakCache#get ProxyClassFactory#apply ,实现了

    2024年02月04日
    浏览(30)
  • cglib动态代理、jdk动态代理及spring动态代理使用

    NickelBeforeAdvice.java方法执行之前 NickelAfterReturningAdvice.java方法执行之后 NickelAroundadvice.java环绕方法 NickelThrowAdvice.java抛异常方法 UserService.java抛异常方法 SpringProxtFactoryTest.java测试方法 NickelStaticMethodMatherPointcut.java方法匹配的方法 NickelPointcutAdvisor.java切面方法 SpringProxtFactoryTest.j

    2024年02月15日
    浏览(36)
  • JDK 代理和 CGLib 有什么区别?

    动态代理是一种机制,程序通过该机制在运行时动态生成代理对象并调用代理方法。动态代理主要有两种实现机制,一种是基于反射动态代理的JDK,另一种是基于ASM动态代理机制的CGLib实现。现在让我们谈谈两种实现之间的区别以及如何实现它们 JDK动态代理采用反射机制实现

    2024年02月09日
    浏览(26)
  • 通俗易懂 快速理解 JDK动态代理 和 cglib动态代理

    动态代理的实现方案有两种, JDK动态代理 和 CGLIB动态代理 ,区别在于JDK自带的动态代理,必须要有接口,而CGLIB动态代理有没有接口都可以。 JDK动态代理 :JDK原生的实现方式,需要被代理的目标类必须实现接口。因为这个技术要求 代理对象和目标对象实现同样的接口 (兄

    2024年02月08日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包