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

Java的代理模式

java有三种代理模式

静态代理

jdk动态代理

cglib实现动态代理

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

 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 {@Overridepublic void play() {System.out.println("播放金刚大战哥斯拉");}
}

创建代理类ProxyMovie.java

public class ProxyMovie implements Movie {Movie movie;public ProxyMovie(Movie movie) {this.movie = movie;}@Overridepublic 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();}
}

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

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

 jdk动态代理

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

public interface Movie {void play();
}

创建实现类RealMovie.java

public class RealMovie implements Movie{@Overridepublic 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;}@Overridepublic 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();}
}

 总结:在这里,代理类没有实现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();}@Overridepublic 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();}
}

 总结:由以上可以看出,使用cglib代理可以代理一些没有父类的目标对象,所以以后如果要代理没有实现接口的类,可以选择使用cglib代理。

相关文章:

Java的代理模式

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

FilterAttributeOnClassMethod

目录 1 BadMethodFilterAttribute 2 FilterAttributeOnClassMethod 2.1 OnMethodExecuted 2.2 OnMethodExecutedAsync 2.3 OnMethodExecuting BadMethodFilterAttribute using System; using System.Threading.Tasks; namespace Flatwhite.Core.Tests.Attributes …...

springboot + (mysql/pgsql) + jpa 多数据源(不同类数据源)

配置文件&#xff1a; spring:datasource:primary:jdbc-url: jdbc:mysql://host:3306/数据库?useUnicodetrue&characterEncodingUTF-8&autoReconnecttrue&failOverReadOnlyfalse&serverTimezoneAsia/Shanghai&zeroDateTimeBehaviorconvertToNullusername…...

【Golang】Golang进阶系列教程--Go 语言 context 都能做什么?

文章目录 前言核心是 Context 接口&#xff1a;包含四个方法&#xff1a;遵循规则WithCancelWithDeadlineWithTimeoutWithValue 前言 很多 Go 项目的源码&#xff0c;在读的过程中会发现一个很常见的参数 ctx&#xff0c;而且基本都是作为函数的第一个参数。 为什么要这么写呢…...

画图干货!14种uml图类型及示例

1. 什么是 UML UML 是统一建模语言的缩写。UML 图是基于 UML&#xff08;统一建模语言&#xff09;的图表&#xff0c;目的是直观地表示系统及其主要参与者、角色、动作、工件或类&#xff0c;以便更好地理解、更改、维护或记录信息关于系统。简而言之&#xff0c;UML 是一种…...

计算机视觉实验:人脸识别系统设计

实验内容 设计计算机视觉目标识别系统&#xff0c;与实际应用有关&#xff08;建议&#xff1a;最终展示形式为带界面可运行的系统&#xff09;&#xff0c;以下内容选择其中一个做。 1. 人脸识别系统设计 (1) 人脸识别系统设计&#xff08;必做&#xff09;&#xff1a;根据…...

振弦采集仪完整链条的岩土工程隧道安全监测

振弦采集仪完整链条的岩土工程隧道安全监测 隧道工程是一种特殊的地下工程&#xff0c;其建设过程及运行期间&#xff0c;都受到各种内外力的作用&#xff0c;如水压、地震、地质变形、交通荷载等&#xff0c;这些因素都会对隧道的安全性产生影响。因此&#xff0c;对隧道的安…...

NLP实战9:Transformer实战-单词预测

目录 一、定义模型 二、加载数据集 三、初始化实例 四、训练模型 五、评估模型 &#x1f368; 本文为[&#x1f517;365天深度学习训练营]内部限免文章&#xff08;版权归 *K同学啊* 所有&#xff09; &#x1f356; 作者&#xff1a;[K同学啊] 模型结构图&#xff1a; &a…...

使用Vue.js和Rust构建高性能的物联网应用

物联网(IoT)应用是现代技术的重要组成部分&#xff0c;它们可以在各种场景中&#xff08;例如智能家居&#xff0c;工业自动化等&#xff09;提供无缝的自动化解决方案。在这篇文章中&#xff0c;我们将探讨如何使用Vue.js和Rust构建高性能的物联网应用。 1. 为什么选择Vue.js…...

idea调节文字大小、日志颜色、git改动信息

idea调节菜单栏文字大小&#xff1a; 调节代码文字大小&#xff1a; 按住ctrl滚动滑轮可以调节代码文字大小&#xff1a; 单击文件即可在主窗口上打开显示&#xff1a; idea在控制台对不同级别的日志打印不同颜色 &#xff1a; “grep console”插件 点击某一行的时候&#x…...

避免大龄程序员边缘化:如何在技术行业中保持竞争力

目录 导语持续学习和进修维护专业形象寻找适合自己的领域构建个人品牌和网络拥抱变化和创新实例结语&#xff1a; 导语 导语&#xff1a;随着科技的不断发展&#xff0c;技术行业的竞争日益激烈。对于那些年龄稍长的程序员来说&#xff0c;如何保持竞争力并避免边缘化成为了一…...

Jenkins工具系列 —— 启动 Jenkins 服务报错

错误显示 apt-get 安装 Jenkins 后&#xff0c;自动启动 Jenkins 服务报错。 排查原因 直接运行jenkins命令 发现具体报错log&#xff1a;Failed to start Jetty或Failed to bind to 0.0.0.0/0.0.0.0:8080或Address already in use 说明&#xff1a;这里提示的是8080端口号…...

华为数通HCIA-实验环境ensp简介

ensp 路由器&#xff1a;AR系列、NE系列&#xff1b; 模拟器中使用AR2220&#xff1b; 交换机&#xff1a;S系列、CE系列&#xff1b; 模拟器中使用S5700&#xff1b; 线缆&#xff1a;copper——以太网链路&#xff1b; serial——串行链路&#xff0c;在模拟器中用于模…...

SK5代理与IP代理:网络安全中的爬虫利器

一、什么是IP代理与SK5代理&#xff1f; IP代理&#xff1a; IP代理是一种允许用户通过代理服务器进行网络连接的技术。用户请求经由代理服务器中转&#xff0c;从而实现隐藏真实IP地址&#xff0c;保护用户隐私&#xff0c;并在一定程度上突破IP访问限制。常见的IP代理有HTTP…...

实战:Prometheus+Grafana监控Linux服务器及Springboot项目

文章目录 前言知识积累什么是Prometheus什么是Grafana怎样完成数据采集和监控 环境搭建docker与docker-compose安装docker-compose编写 监控配置grafana配置prometheus数据源grafana配置dashboardLinux Host Metrics监控Spring Boot 监控 写在最后 前言 相信大家都知道一个项目…...

[用go实现解释器]笔记1-词法分析

本文是《用go实现解释器》的读书笔记 ​ https://malred-blog​malred.github.io/2023/06/03/ji-suan-ji-li-lun-ji-shu-ji/shi-ti/go-compile/yong-go-yu-yan-shi-xian-jie-shi-qi/go-compiler-1/#toc-heading-6http://个人博客该笔记地址 ​github.com/malred/malanghttp:/…...

在 spark-sql / spark-shell / hive / beeline 中粘贴 sql、程序脚本时的常见错误

一个很小的问题&#xff0c;简单记录一下。有时候我们会粘贴一段已经成功运行过的SQL或程序脚本&#xff0c;但是在spark-sql / spark-shell / hive / beeline 中执行时可能会报这样的错误&#xff1a; hive> CREATE EXTERNAL TABLE IF NOT EXISTS ORDERS(> Display all…...

关于视频汇聚融合EasyCVR平台多视频播放协议的概述

视频监控综合管理平台EasyCVR具备视频融合能力&#xff0c;平台基于云边端一体化架构&#xff0c;具有强大的数据接入、处理及分发能力&#xff0c;平台既具备传统安防视频监控的能力与服务&#xff0c;也支持AI智能检测技术的接入&#xff0c;可应用在多行业领域的智能化监管场…...

三星书画联展:三位艺术家开启国风艺术之旅

7月22日&#xff0c;由广州白云区文联、白云区工商联主办的“三星书画联展”&#xff0c;在源美术馆正式开展。本次书画展展出的艺术种类丰富&#xff0c;油画、国画、彩墨画、书法等作品异彩纷呈。广东省政协原副主席、农工党省委书画院名誉院长马光瑜&#xff0c;意大利艺术研…...

在腾讯云服务器OpenCLoudOS系统中安装nginx(有图详解)

1. 创建安装目录 2. 下载、安装、编译 进入安装目录&#xff1a; cd /app/soft/nginx/ 下载&#xff1a; wget https://nginx.org/download/nginx-1.21.6.tar.gz 解压&#xff1a; tar -zxvf nginx-1.21.6.tar.gz 安装插件&#xff1a; yum -y install pcre-devel 安装…...

大数据课程E5——Flume的Selector

文章作者邮箱:yugongshiye@sina.cn 地址:广东惠州 ▲ 本章节目的 ⚪ 了解Selector的概念和配置属性; ⚪ 掌握Selector的使用方法; 一、简介 1. 概述 1. Selector本身是Source的子组件,决定了将数据分发给哪个Channel。 2. Selector中提供了两种模式: …...

在线查看浏览器

随着网络的兴起&#xff0c;电影和电视剧已经成为我们生活中必不可少的乐趣。然而&#xff0c;像爱奇艺、优酷、腾讯、芒果等等这些平台&#xff0c;我们想要看好视频&#xff0c;需要开通VIP&#xff0c;虽然价格不是很高&#xff0c;但是我们能省则省啊&#xff0c;今天我就给…...

谷粒商城第七天-商品服务之分类管理下的分类的拖拽功能的实现

目录 一、总述 1.1 前端思路 1.2 后端思路 二、前端实现 2.1 判断是否能进行拖拽 2.2 收集受影响的节点&#xff0c;提交给服务器 三、后端实现 四、总结 一、总述 这个拖拽功能对于这种树形的列表&#xff0c;整体的搬迁是很方便的。但是其实现却并不是那么的简单。 …...

解决单节点es索引yellow

现象 单节点的es&#xff0c;自动创建索引后&#xff0c;默认副本个数为1&#xff0c;索引状态为yellow 临时解决 修改副本个数为0 永久解决 方法1、修改elasticsearch.yml文件&#xff0c;添加配置并重启es number_of_replicas&#xff1a;副本分片数&#xff0c;默认…...

Java虚拟机在类加载阶段都做了些什么,才使得我们可以运行Java程序

前言&#xff1a; 今天和大家探讨一道Java中经典的面试题&#xff0c;这道面试题经常出现在各个公司的面试中&#xff0c;结合周志明&#xff0c;老师的《深入理解Java虚拟机》书籍&#xff0c;本篇文章主要讲解Java类加载机制的知识。该专栏比较适合刚入坑Java的小白以及准备秋…...

华为认证 | 学HCIE,想培训需要注意啥?

HCIE&#xff08;华为认证网络专家&#xff09;是华为技术认证体系中的最高级别认证&#xff0c;对于网络工程师来说考试难度也比较高&#xff0c;一般来说&#xff0c;需要进行培训。 那么HCIE考试培训需要注意啥&#xff1f; 01 充分了解认证要求 在开始准备HCIE认证之前&a…...

这所211考数一英二,学硕降分33分,十分罕见!

一、学校及专业介绍 合肥工业大学&#xff08;Hefei University of Technology&#xff09;&#xff0c;简称“合工大”&#xff0c;校本部位于安徽省合肥市&#xff0c;是中华人民共和国教育部直属的全国重点大学&#xff0c;是国家“双一流”建设高校&#xff0c; 国家“211工…...

关于BQ27427的配置问题

EVM是TI家做的BQ27427的开发板&#xff0c;这款芯片还挺新的。 大概是这样&#xff0c;一块开发板要一千多块钱&#xff0c;使用的时候还出现了一些奇怪的问题。 配置使用的是买的盗版的EV2400&#xff0c;就是黑色的那个东西&#xff0c;使用的通信方式IIC。 TI手册上写的软件…...

试卷还原成空白卷怎么做?分享个简单的方法

在进行考试时&#xff0c;可能会填错答案或想要重新测试&#xff0c;此时需要正确擦除填写的试卷答案。下面介绍一些需要注意的事项以及正确的擦除方法。 使用橡皮擦或橡皮 正确的擦除方法是使用橡皮擦或橡皮对填写的答案进行擦除。首先&#xff0c;将橡皮擦或橡皮放置在试卷上…...

查看学校名称中含北京的用户

查看学校名称中含北京的用户_牛客题霸_牛客网 1.like select device_id,age,university from user_profile where university like %北京%; 注意虽然按实际需求&#xff0c;北京一般是排在最前面&#xff0c;即北京%&#xff0c;但是严格意义上来说&#xff0c;搜索含有北京…...