Java的代理模式

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

java有三种代理模式

静态代理

jdk动态代理

cglib实现动态代理

代理模式的定义: 为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
Java的代理模式,java,代理模式,开发语言

 java的三种代理模式优缺点

静态代理 jdk动态代理

cglib实现动态代理

简单易懂:静态代理模式的实现相对简单,易于理解和使用。代理类在编译时就已经存在,开发人员可以直接通过编码方式创建和配置代理对象。

可以在代理类中添加额外的逻辑:通过静态代理,我们可以在代理类中添加额外的逻辑,如安全检查、日志记录、性能监控等,而无需修改被代理类的代码。这种方式使得代理类具有更高的灵活性和扩展性。

控制访问权限:静态代理可以控制对被代理对象的访问权限。代理类可以添加一些条件或限制,以决定是否调用被代理类的方法,从而实现对被代理对象的权限控制。

低耦合:通过静态代理,被代理类和代理类是相互独立的,彼此并无直接的依赖关系。这种低耦合的设计能够降低系统的复杂性,提高代码的可维护性和可测试性。

可以对多个对象进行代理:静态代理模式可以对多个对象进行代理,这样我们可以在不改变原始对象的情况下,通过代理对象来进行统一的管理和控制。

  

简化代理模式实现:相比于静态代理,JDK动态代理通过反射机制实现,无需手动编写大量的代理类代码。只需要编写一个代理处理器即可,大大简化了代理模式的实现过程。

可以代理任意接口:JDK动态代理是基于接口的代理,可以代理任意实现了接口的类。这意味着无论被代理类的具体实现如何,只要实现了接口,就可以使用JDK动态代理进行代理操作。

代码结构清晰:使用JDK动态代理,代理类和被代理类之间的关系更加清晰。代理类实现了InvocationHandler接口,可以在方法调用前后添加自定义逻辑,而被代理类则专注于核心业务逻辑的实现。这样有利于代码的维护和扩展。

可以动态改变代理行为:由于代理类是在运行时动态生成的,可以在代理类中灵活地修改和调整代理行为。可以根据实际需要,在不修改被代理类代码的情况下,通过修改代理处理器的逻辑,实现不同的代理行为。

高性能:相比于CGlib等其他动态代理实现,JDK动态代理在性能上具有较好的表现。JDK动态代理使用Java原生的反射机制,在执行方法调用时会有一些性能损耗,但仍然比一些其他动态代理实现方式更高效。

      

无需接口:CGLib可以为非接口类生成代理,这意味着我们可以代理那些没有实现任何接口的类。相比于JDK动态代理需要目标类实现接口的限制,CGLib的使用更加灵活。

高性能:CGLib采用了底层的字节码操作技术,通过生成目标类的子类,并重写其中的方法来实现代理。相比于JDK动态代理的反射调用,CGLib的代理调用更快速,性能更高效。

简化代理:CGLib可以在运行时生成代理类,避免了编写很多重复的代理类代码的麻烦。它通过继承来实现代理,这样我们就可以专注于业务逻辑的实现,而无需关心代理类的创建和管理。

支持回调过滤:CGLib提供了MethodInterceptor接口,可以在代理类的方法调用前后插入自定义的逻辑。这允许我们在目标方法执行前后进行一些额外的处理,如日志记录、权限校验、缓存等。

可扩展性强:CGLib是一个功能强大的库,除了可以实现动态代理外,还可以用于AOP编程、实现Bean的动态注入等。它提供了丰富的API和扩展点,可以根据实际需求进行灵活的扩展和定制。

代码复杂度增加:使用静态代理会引入额外的代理类,从而增加代码的复杂性。每个被代理类都需要对应一个代理类,随着被代理类的增加,代理类的数量也会增加,导致代码变得冗长且难以维护。

频繁更新代理类:如果被代理类的接口发生变化,代理类也需要相应地进行修改。这意味着在使用静态代理时,每次接口发生变动,需要手动更新相关的代理类,增加了维护成本和风险。

静态代理不支持动态代理:静态代理是在编译时期生成的代理类,对于动态生成的对象,无法进行代理。如果需要对一批动态生成的对象进行代理,静态代理就显得无能为力。

单一职责原则破坏:静态代理中代理类与被代理类紧密耦合,代理类不仅要实现接口方法的委托,还要添加额外的逻辑。这样可能导致代理类承担了过多的责任,违反了单一职责原则。

动态扩展困难:静态代理在代理类定义时就已经确定了被代理对象,如果需要代理新的类或者对象,就要重新编写对应的代理类。这种静态的特性使得动态扩展变得困难,难以应对频繁变化的需求。

只能代理接口:JDK动态代理只能代理实现了接口的类,对于没有实现接口的类,无法进行代理。这一限制使得某些类无法使用JDK动态代理,需要考虑其他代理实现方式。

性能有一定损耗:JDK动态代理使用反射机制,在方法调用时会涉及到反射操作,这会引入一定的性能损耗。相比起静态代理,JDK动态代理的性能稍差一些。对于对性能要求较高的场景,可能需要考虑其他更高效的代理实现方式。

无法代理私有方法:JDK动态代理只能代理公开的方法,无法代理私有方法。这是由于代理机制是基于接口生成的动态代理类,无法直接访问类的私有成员。

需要实现InvocationHandler接口:使用JDK动态代理,需要编写一个实现InvocationHandler接口的代理处理器类。虽然这使得动态代理实现更加灵活,但同时也增加了开发的复杂性。

无法直接修改被代理类:JDK动态代理是通过代理接口生成代理类,而不是直接修改被代理类的字节码。这一特性使得在不修改被代理类的情况下无法对其进行修改或添加新的行为。

类加载器限制:CGLib使用了底层的字节码操作技术来生成代理类,这需要在运行时动态创建和加载类。某些情况下,类加载器限制可能会导致无法使用CGLib动态代理,例如在一些受限的环境下或者使用特定的类加载器。

需要依赖第三方库:CGLib是一个第三方库,不是Java的标准库。使用CGLib时需要将其引入项目中并进行相应的配置,增加了项目的依赖。

Proxy无法代理final方法:CGLib的动态代理无法代理final方法,因为final方法无法被子类重写。如果目标类中存在final方法,CGLib将无法为其生成代理,这在一些特定场景下可能会有限制。

难以调试:使用CGLib生成的代理类是动态生成的字节码,对于开发者来说可读性较差。对于调试代理类的问题或者理解代理逻辑,可能需要额外的工具和技巧。

内存占用较高:由于CGLib是通过生成代理类的子类来实现的,每次代理都会创建一个新的类,并加载到JVM中。如果频繁地创建代理对象,可能会产生大量的代理类,增加内存占用。

静态代理

先创建一个父类或者接口,被代理对象和代理对象都应该继承父类或者实现接口。
创建接口Movie.java

public interface Movie {
    void play();
}

 创建实现类RealMovie.java

public class RealMovie implements Movie {
    @Override
    public void play() {
        System.out.println("播放金刚大战哥斯拉");
    }
}

创建代理类ProxyMovie.java

public class ProxyMovie implements Movie {
    Movie movie;

    public ProxyMovie(Movie movie) {
        this.movie = movie;
    }

    @Override
    public void play() {
        System.out.println("电影还没开始,买点爆米花");
        movie.play();
        System.out.println("电影结束了,买个哥斯拉模型");
    }
}

创建测试类Test.java

public class Test {
    public static void main(String[] args) {
        RealMovie movie = new RealMovie();
        ProxyMovie proxyMovie = new ProxyMovie(movie);
        proxyMovie.play();
    }
}

Java的代理模式,java,代理模式,开发语言

 总结:在不改变RealMovie的前提下,使用ProxyMovie对其进行了增强。但是由于目标对象和代理对象都实现了同一个接口,一旦这个接口添加或者删除方法,那么代理对象和目标对象都要进行相应的操作,耦合度太高。

静态代理的应用:在使用实现Runnable接口实现多线程的时候,将Runnable接口的实现类的对象作为Thread的构造函数的参数

Java的代理模式,java,代理模式,开发语言

 jdk动态代理

为了解决静态代理的代理类必需实现接口的所有方法的问题,动态代理诞生了,java的动态代理有如下的特点:
1、代理对象不需要跟目标对象实现同一接口或继承同一个父类(解决了静态代理的痛点);
2、代理对象的生成利用jdk提供的api,在JVM内存中动态的构建代理对象。
创建接口Movie.java

public interface Movie {
    void play();
}

创建实现类RealMovie.java

public class RealMovie implements Movie{
    @Override
    public void play() {
        System.out.println("播放侏罗纪世界");
    }
}

创建代理类ProxyMovie.java

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class ProxyMovie implements InvocationHandler {
    private Object movie;

    public ProxyMovie(Object movie) {
        this.movie = movie;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("电影还没开始,买瓶可乐");
        method.invoke(movie, args);
        System.out.println("电影还结束,买一只恐龙模型");
        return null;
    }
}

创建测试类Test.java

public class Test {
    public static void main(String[] args) {
        RealMovie realMovie = new RealMovie();
        InvocationHandler proxyMovie = new ProxyMovie(realMovie);
        // 创建代理对象
        Movie movie = (Movie)Proxy.newProxyInstance(realMovie.getClass().getClassLoader(), realMovie.getClass().getInterfaces(), proxyMovie);
        System.out.println(movie.getClass().getSimpleName());
        movie.play();
    }
}

Java的代理模式,java,代理模式,开发语言

 总结:在这里,代理类没有实现Movie接口,而是实现了InvocationHandler接口,然后重写了invoke方法,与Movie接口的耦合度降低。

cglib实现动态代理

在使用jdk动态代理时,被代理对象是实现了一个接口的,假如实际中被代理对象没有实现接口该怎么办呢,cglib动态代理便应运而生,原理是创建一个目标对象的子类对象,然后进行增强操作,所以被代理对象的类不能是final类型的(无法被继承,也就没有子类),被调用的方法也不能是final和static类型的(不会执行代理功能)。
在pom.xml文件中添加cglib依赖

<dependency>
	<groupId>cglib</groupId>
	<artifactId>cglib</artifactId>
	<version>3.3.0</version>
</dependency>

创建CglibService.java

public class CglibService {
    public void movie() {
        System.out.println("播放侏罗纪公园");
    }
}

创建CglibServiceProxy.java类

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibServiceProxy implements MethodInterceptor {
    private Object object;

    public CglibServiceProxy(Object object) {
        this.object = object;
    }

    public Object getProxyInstance() {
        //创建代理类
        Enhancer enhancer = new Enhancer();
        //继承要被代理的类
        enhancer.setSuperclass(object.getClass());
        //设置回调函数
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("电影即将开始,大家有序进入影厅");
        Object obj = method.invoke(object);
        System.out.println("电影结束,大家离开电影院");
        return obj;
    }
}

创建CglibProxyTest.java

public class CglibProxyTest {
    public static void main(String[] args) {
        CglibService service = new CglibService();
        CglibServiceProxy proxy = new CglibServiceProxy(service);
        CglibService proxyInstance = (CglibService)proxy.getProxyInstance();
        proxyInstance.movie();
    }
}

Java的代理模式,java,代理模式,开发语言

 总结:由以上可以看出,使用cglib代理可以代理一些没有父类的目标对象,所以以后如果要代理没有实现接口的类,可以选择使用cglib代理。文章来源地址https://www.toymoban.com/news/detail-613488.html

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

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

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

相关文章

  • Java 与设计模式(13):代理模式

    代理模式是一种结构型设计模式,用于在访问对象时引入一个代理对象,以控制对实际对象的访问。代理对象充当了客户端和实际对象之间的中介,客户端通过代理对象间接地访问实际对象,从而可以在访问过程中添加额外的逻辑或控制。代理模式可以提供对实际对象的保护

    2024年02月09日
    浏览(28)
  • 基于Java的设计模式 - 代理模式

    代理模式是一种使用代理对象来执行目标对象的方法并在代理对象中增强目标对象方法的一种设计模式。简单来讲就是在不修改目标对象的基础上,增强主业务逻辑的设计模式。 代理模式基本可分为三种 静态代理 JDK动态代理 CGLIB动态代理 上述简单分就是静态和动态代理,静

    2024年02月07日
    浏览(29)
  • 代理模式(Java实现)

    代理模式是常见的设计模式之一,顾名思义,代理模式就是代理对象具备真实对象的功能,并代替真实对象完成相应操作,并能够在操作执行的前后,对操作进行增强处理。(为真实对象提供代理,然后供其他对象通过代理访问真实对象) 分为 静态代理 动态代理 jdk动态代理

    2024年02月12日
    浏览(29)
  • Java的代理模式

    java有三种代理模式 静态代理 jdk动态代理 cglib实现动态代理 代理模式的定义: 为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。  java的三种代理模式

    2024年02月15日
    浏览(17)
  • Java 代理模式

    目标类和代理类,不是直接调用目标类对象,而是通过调用代理类的对象的方法,代理类来帮我们访问目标类对象,这样我们就可以在代理类上添加更多需要的扩展功能,而目标类不用改动,只用实现自身的主要功能。 代理类是为了扩展目标类的功能,代理类和目标类的产出

    2024年02月10日
    浏览(21)
  • 代理模式(java)

    目录 结构 静态代理案例  代码实现 售票类 火车站类 代理类 测试类 优缺点 优点 缺点 代理(Proxy)模式分为三种角色: 抽象主题(Subject)类 : 通过接口或抽象类声明真实主题和代理对象实现的业务方法。 真实主题(Real Subject)类 : 实现了抽象主题中的具体业务,是代理

    2024年02月16日
    浏览(23)
  • java代理模式

    比如现在项目经理有一个需求:在项目现有所有类的方法前后打印日志。如何实现? 静态代理是在编译的时候就将实现类和代理类编程了字节码class文件,然后加载到JVM中。 程序员要手动为每一个目标类编写对应的代理类。如果当前系统已经有成百上千个类,工作量太大了。

    2024年02月13日
    浏览(20)
  • Java研学-代理模式

    1 分类   静态代理:在程序运行前就已经存在代理类的字节码文件,代理对象和真实对象的关系在运行前就确定了。(代理类及对象要自行创建)   动态代理:代理类是在程序运行期间由 JVM 通过反射等机制动态的生成的,不存在代理类的字节码文件,动态生成字节码对

    2024年01月25日
    浏览(32)
  • Java 代理模式详解

    本博主将用CSDN记录软件开发求学之路上亲身所得与所学的心得与知识,有兴趣的小伙伴可以关注博主!也许一个人独行,可以走的很快,但是一群人结伴而行,才能走的更远! 代理模式是一种比较好理解的设计模式。简单来说就是 我们使用代理对象来代替对真实对象(real

    2024年02月06日
    浏览(20)
  • Java中的代理模式

    接口 目标类 代理类 测试 接口 目标类 动态代理类 测试 总结: 动态生成代理类 通过实现接口生成代理类(目标接口必须实现接口) 代理类是实现接口的方式 调用目标类使用反射调用 目标类调用本类方法只会代理一次 目标类 代理类 测试 总结 通过ASM第三方框架动态代理 无需接

    2024年02月15日
    浏览(28)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包