java代理模式静态代理与动态代理Arebirth

在学习代理模式的时候我首先要提出几个问题,

1、什么是代理模式?

举个例子吧:我们生活中的租房问题。假如我们去租个房子,我们大多数情况下是不会知道房主(就是真正租房,一手货源)的,我们是不是都是先去某些租房平台,或者去找当地的中介去询问何时的房子。我们通过九牛二虎之力在中介那里找到了个物美价廉的房子后,你的租金是不是交给了中介,中介还会收取一些额外的推荐费啦,押金啦、手续费等之类的,那么好,这样的一小段,就已经出来了其中两大核心对象了。

房主(把房子交给中介的人):被代理对象

中介(租给你房子的人):代理对象

2、代理模式有哪些作用?

1.可以隐藏目标的的具体实现(还是拿上面租房的例子来说,房主把房子交给了中介,并和中介谈好了价格我7你3啊。然后当我们去租房子的时候,是中介正面把房子租给了我们,而真正背后卖房子的并未出面,这样就隐藏了背后人的信息和提高了背后人的安全)

2.可以在不修改目标类代码的情况下,对其增加新的功能。(上面例子来说:房东把房子交给中介的时候价格可能只有1000,但是房东可以卖到5000,然后卖出去后在把1000给房东,自己收入4000,这样原房东不但收到了应由的钱,中介还收入了更多的额外费用)。

3、代理模式有哪几种?分别都有什么不同?

在我们Java程序中代理模式分为:静态代理和动态代理(动态代理又分为:JDK动态代理和CGLIB动态代理)

至于什么不同,接下来正式我们着重要学习的内容

什么是静态代理呢?

具体实现:

被代理类与代理类共同实现的接口

packagecn.arebirth.staticproxy;/***需要实现的共同接口*因为要保证代理类要不改变被代理类原来功能的基础上增加新的功能*/publicinterfaceRentalHouse{/***出租房子*/voidrent();}被代理类(房东)

packagecn.arebirth.staticproxy;/***房东(目标类、被代理类)*/publicclassHostimplementsRentalHouse{@Overridepublicvoidrent(){System.out.println("我是房东,出租500平米的大房子");}}代理类(中介)

packagecn.arebirth.staticproxy;/***静态代理类(中介、代理类)*注意:需要被代理类实现相同的接口*/publicclassStaticProxyimplementsRentalHouse{privateRentalHouserentalHouse;publicStaticProxy(RentalHouserentalHouse){this.rentalHouse=rentalHouse;}@Overridepublicvoidrent(){System.out.println("我是中介,收你500推荐费");//调用被代理类的租房方法rentalHouse.rent();System.out.println("我是中介,我又想收你1000块钱!");}}测试类

packagecn.arebirth.staticproxy;publicclassTest{publicstaticvoidmain(String[]args){//创建被代理度下行Hosthost=newHost();/***创建代理对象,并把被代理对象传递给代理对象,*因为他们都实现相同的接口,实现了相同的方法,这样的话传递的对象可以是房东1房东2...*/StaticProxyproxy=newStaticProxy(host);proxy.rent();}}输出结果:我是中介,收你500推荐费我是房东,出租500平米的大房子我是中介,我又想收你1000块钱!

试想一下,如果有两个房东,三个,四个,甚至更多个房东的话,我们怎么写?

被代理类

packagecn.arebirth.staticproxy;/***房东1(目标类、被代理类)*/publicclassHost1implementsRentalHouse{@Overridepublicvoidrent(){System.out.println("我是房东1,出租500平米的大房子");}}packagecn.arebirth.staticproxy;/***房东2(目标类、被代理类)*/publicclassHost2implementsRentalHouse{@Overridepublicvoidrent(){System.out.println("我是房东2,出租500平米的大房子");}}

代理类(中介)

packagecn.arebirth.staticproxy;/***静态代理类(中介、代理类)*注意:需要被代理类实现相同的接口*/publicclassStaticProxyimplementsRentalHouse{//什么价位的房子privateintmoneuy;publicAgent(intmoneuy){this.moneuy=moneuy;}@Overridepublicvoidrenting(){//出租房东的租房//中介调用的租房方法仍然是房东的租房方法System.out.println("收取50元推荐费");if(moneuy<=800){//金额小于等于800的时候Host1host=newHost1();host.rent();}else{Host2host=newHost2();host.rent();}System.out.println("收取500元押金费用");}}测试类

publicclassTest{publicstaticvoidmain(String[]args){StaticProxyproxy=newStaticProxy(1000);proxy.renting();}}输出结果:我是房东2,出租500平米的大房子

静态代理的缺点:

我们仔细来观察下,随着我们的被代理对象的增多,也是就是房东越来越多,那我们的被代理类就会越来越冗余,中介的压力也就会越来越大。

常用的动态代理又分为JDK动态代理和CGLIB动态代理

那么两者的使用场景又是什么呢??

如果目标对象实现了接口,就是上面我们举到的例子,房东和中介共同实现的接口类似,这样的话就采用JDK动态代理

如果目标对象没有实现接口,必须采用CGLIB动态代理

要实现的共同接口

packagecn.arebirth.jdkproxy;/***需要实现的共同接口*/publicinterfaceRentalHouse{/***出租房子*/voidrent();}房东(被代理对象)

packagecn.arebirth.jdkproxy;/***房东(目标类、被代理类)*/publicclassHostimplementsRentalHouse{@Overridepublicvoidrent(){System.out.println("我是房东,出租500平米的大房子");}}核心来了!(JDK动态代理实现类)packagecn.arebirth.jdkproxy;

packagecn.arebirth.jdkproxy;publicclassTest{publicstaticvoidmain(String[]args){//创建JdkProxy动态代理对象类,并把需要被代理的对象传递进去JdkProxyjdkProxy=newJdkProxy(newHost());//获得代理类这里一定要写他们共同实现的接口利用java多态的特性,如果直接写真实类型是会报错的RentalHouseproxy=(RentalHouse)jdkProxy.getProxy();proxy.rent();}}输出结果:我是中介,收你500推荐费我是房东,出租500平米的大房子我是中介,我又想收你1000块钱!

我想当你看到这里一定会感到困惑,为什么我们获取到了代理对象后执行的执行代理对象的方法,明明是房东的方法,怎么显示的好像是JDK动态代理类里面的invoke()方法??或许还有其他的困惑,我们将在下边一一讲解如何实现的原理。

既然想知道如何实现的,那么我们就要从底层出发,来看看,底层的Proxy代理到底帮我们生成了一个怎样的代理类。

再开始之前我希望接下来的代码与操作你是跟着我同步进行的,这样子才会更深刻有更好的理解,当然不排除你是个人脑机器模拟器

开始吧!

我们想要看底层如何实现的,那么我们首先就要获得代理类的class文件

下面是我写的一个获取JDKProxy动态代理所生成的代理文件的工具类

packagecn.arebirth.jdkproxy;importsun.misc.ProxyGenerator;importjava.io.File;importjava.io.FileOutputStream;importjava.io.FileWriter;importjava.io.IOException;publicclassProxyUtil{/***@paramproxyName生成文件代理类的名字*@paraminterClass代理类所实现的接口的class数组形式*@parampath写出路径*/publicstaticvoidwriteProxyClassToHardDisk(StringproxyName,Class[]interClass,Stringpath){byte[]bytes=ProxyGenerator.generateProxyClass(proxyName,interClass);FileOutputStreamout=null;try{out=newFileOutputStream(path+File.separator+proxyName+".class");out.write(bytes);out.flush();}catch(IOExceptione){e.printStackTrace();}finally{try{if(out!=null)out.close();}catch(IOExceptione){e.printStackTrace();}}}}然后我们在测试类里面使用它

packagecn.arebirth.jdkproxy;publicclassTest{publicstaticvoidmain(String[]args){//创建JdkProxy动态代理对象类,并把需要被代理的对象传递进去JdkProxyjdkProxy=newJdkProxy(newHost());//获得代理类RentalHouseproxy=(RentalHouse)jdkProxy.getProxy();proxy.rent();//写入JDK动态代理生成的代理类ProxyUtil.writeProxyClassToHardDisk(proxy.getClass().getSimpleName(),proxy.getClass().getInterfaces(),"F:\\Tools\\DevelopmentTools");}}

最后生成出来的代理类是一个class字节码文件,我们需要使用反编译工具来查看,我使用的是Luten(这个工具打开方式特殊,百度自行查找)

super.h.invoke(this,$Proxy0.m3,null);那么super是谁?就是它自动继承的Proxy类

那么h是什么?就是Proxy类的InvocationHandler

那么我们看这个InvocationHandler类是不是感觉有那么一丢丢的眼熟啊,回过头看,这就是我们在写JDK动态代理类的时候实现的那个接口。

!!!!!!!!!!!!!

然后它又调用了invoke(this,$Proxy0.m3,null);

第一个参数:代理类对象

第二个参数:要执行的代理类对象的方Method对象,这个Method对象的值已经由我们的编译器帮我们构建好了,我们只需要第一个次加载这个类的时候他就会自动赋值了(static代码块)

第三个参数:方法里面的参数,当没有参数的时候就是NULL

带着你的疑惑,从头在开始好好敲一遍代码,捋一遍,相信我,你将有更大的收货!!

下面是简略画的思路图,试着用画图来画出你的思维

是不是这个JDK动态代理必须要依赖接口才能实现,如果没有接口的话,那么JDK动态代理也就凉凉了对吧,!

那么好,接下来我们将说一种更加强大的动态代理方式CGLIB,它的实现原理只要我们懂了JDK动态代理,那么下面的就是小儿科啦哈哈~

CGLIB的代理将不再需要接口也可以生成代理类,但是它需要导包!

当然,你也可以选择其他版本的JAR包!

===

开始

packagecn.arebirth.cglibproxy;/***被代理类*/publicclassHost{publicvoidrent(){System.out.println("Host:rentalhouse");}}生成代理对象的cglib类

packagecn.arebirth.cglibproxy;importnet.sf.cglib.proxy.Enhancer;importnet.sf.cglib.proxy.MethodInterceptor;importnet.sf.cglib.proxy.MethodProxy;importjava.lang.reflect.Method;publicclassCglibProxyimplementsMethodInterceptor{/***获取代理类**@return*/publicObjectgetProxy(){Enhancerenhancer=newEnhancer();//设置被代理对象enhancer.setSuperclass(Host.class);//设置回调方法当前对象enhancer.setCallback(this);//创建代理对象Objecto=enhancer.create();returno;}/***@paramo被代理对象*@parammethod被代理对象方法*@paramobjects被代理对象方法中的参数*@parammethodProxy代理类中的方法*@return*@throwsThrowable*/@OverridepublicObjectintercept(Objecto,Methodmethod,Object[]objects,MethodProxymethodProxy)throwsThrowable{System.out.println("中介收取手续费");Objecto1=methodProxy.invokeSuper(o,objects);System.out.println("中介收取中介费");returno1;}}测试类

packagecn.arebirth.cglibproxy;publicclassTest{publicstaticvoidmain(String[]args){CglibProxycglibProxy=newCglibProxy();Hostproxy=(Host)cglibProxy.getProxy();//强制转换为我们的房主proxy.rent();}}输出结果:中介收取手续费Host:rentalhouse中介收取中介费

我们动态代理的最大好处就是,可以在没有接口的情况下,只有一个类,我们就可以动态的代理,在程序运行的时候动态的为他创建代理类

最后让我们大概的总结下:

代理模式:静态代理动态代理:JDK动态代理CGLIB动态代理

代理模式的三个要素A.抽象的类或接口完成一件怎样的事情B被代理对象事情操作具体内容C代理对象帮助我们完成事情的同时可以增加其他的东西

具体的列子:我们找中介租房子A抽象的类或者接口租房子B被代理对象房东C代理对象中介

代理模式的好处A房东可以安心的做自己的事情(被代理对象可以做自己的事情)B我们有了问题可以直接找中介(被代理对象变得比较安全)C可以增强代码的扩展性

JDK动态代理和CGLIB动态代理的使用场景

我们可以这样记一下,只要被代理类没有实现接口,我们就必须使用CGLIB动态代理

THE END
1.全国房屋短租网找房子自家房屋!不收中介费!玫瑰园!西三教!可短租!格调春天拎包住 自家房屋!不收中介费!玫瑰园!西三教!可短租!格调春天拎包住 2024-12-5 可月付短租四号线苏州湾东吾悦广场附近萃雅苑房屋出租标价 可月付短租四号线苏州湾东吾悦广场附近萃雅苑房屋出租标价 2024-12-9 0中介 自家房屋 大阳台 玉龙路 可月付https://m.58.com/w/ppkchuzu668/
2.北京中关村搜狐大厦附近上班,在哪租房子合适?2. 预算限制:根据您的预算情况,我们可以考虑不同价位的房源。一般来说,在中关村地区租房价格相对较高https://ask.zol.com.cn/x/25586272.html
3.外贸业务员访谈感想(通用8篇)11、您在这边有房子还是租房子? 租房子。 12、房价怎么样? 很少啊。 13、一个人住还是合租? 一个人住。 14、平时定期会寄钱回家吗?还是自己留着? 家里面不要我的钱。一般都是自己留着。 15、扬州消费怎么样? 扬州这边还行,上海那边高一点,那边工资也高。 https://www.360wenmi.com/f/filerdoc5x9d.html
4.求问大家租房子都在哪里租啊。?小惠子 楼主 2014-02-23 13:08:05 最近我也要租房子,兰州的房租不是一般的高啊。 包子大的雪 快哭了。。。 赞 回应 凤阁 (使人愚蔽者,爱与欲也) 2014-02-23 13:41:50 找中介呗~ 赞 回应 哈士奇金毛萨摩 (吟游诗人。) 2014-02-23 13:49:53 你要租哪?合租还是单租? 赞 回应 https://www.douban.com/group/topic/49401990/?cid=617832243
5.租房找房东直租在哪找怎么找房子租房便宜→MAIGOO知识摘要:外出工作免不了要租房,如今房屋租赁市场上有房东直租、中介、房屋托管、长租公寓等几种常见租房方式,可能很多朋友都喜欢找房东直租的房子。那么租房找房东直租在哪找?怎么找房子租房便宜?房东直租的房子一般价格比较便宜且没有中介费,我们可以通过熟人介绍,或者去小区里面的公告栏找招租信息,下面一起来详细了解https://www.maigoo.com/goomai/230461.html
6.租房房源app排行榜前十名十大相关软件专辑 租房子用什么APP好?租房必备手机APP推荐个人房源租房app租房真实房源app免中介费的租房软件国内短租房app北京租房子app房源管理软件租房平台app租房平台租房子app广州租房子app合租房子app租房买房app大连租房软件个人房东租房软件房车租赁app租房管理app北京日租房apphttps://m.pianwan.com/s/zj-2804238
7.在菲律宾怎样才能租到便宜的房子呢(最实用的租房攻略)远在菲律宾打工的中国热你非常多,出门打工大家都想多赚点钱回家,所以说在菲律宾就想要租便宜一点的房子,那么在菲律宾怎样才能租到便宜的房子呢 在菲律宾租房子的方法有哪些 大家可以去菲律宾本地的最大当地信息网站olx.ph找需要自已的房子,去那里找相对找的到较便宜的房子,但要注意是不是骗子。也可以直接去大楼https://www.527uu.net/news/4519.html
8.月租房在哪里找,日租房在哪里找呢一、平台找短租房 1、现在各大租房网站上有很多个人发布的房源信息,里面有个人和中介公司发布的房源信息,记得选择个人租房的,现在很多年轻人都在上面租房子,一般条件都写的很清楚的,一但有好的房源下手要快,因为在网上找房子的人很多,搞不好都被抢租了。 https://www.duote.com/tech/202312/522770.html
9.租房子一般不租哪几个楼层文章摘要:出门在外工作是要租房的,但是租房需要注意一些事情,比如选择楼层,那么租房子一般不租哪几个楼层? 租房子一般不租底层和顶层。首先底楼的光照不好,这样就会导致房屋阴暗潮湿。其次,底楼的安全性较差,要注意防盗问题。厕所也容易堵,蚊虫也会较多,如果遇到阴雨天气,底楼也常常会有异味。其次就是顶层,顶楼在夏季https://m.loupan.com/bk/134771.htm
10.英国胡弗汉顿大学百问百答95. 在胡弗汉顿大学读书期间可以自己出去租房子吗? 学生可以选择住在校外,住宿费用一般为每周30-50 英镑(不包括水、电、气),学校将为学生提供相关信息。 96. 胡弗汉顿的学生经常用什么交通工具呢? 自行车方便、灵活、经济,是代步的好工具。许多英国学生都用它往来于学校和周边地区。日常交通:巴士(Coach)是最便宜http://www.jladi.com/2011/1207/c707a14032/pagem.htm
11.租房如何找房源?附近哪有房子出租?[摘要]可以了解租房如何找房源以及附近哪有房子出租,或者是有专业的中介进行介绍,那么往往就会节省很多精力,就可以保障不错的租房子效率。下面介绍的就是这方面内容,希望可以帮助大家更快找到房源。 有些人找房子到时候会花很多时间,主要原因是没有找到正规的房源途径,或者是没有找到合格的中介。要是可以了解租房如何https://zhishi.fang.com/zf/qg_563555.html
12.附近日租房从哪里找现在租房的类型有很多,有年租房,月租房和日租房,其中日租房比较适合那些短期居住的朋友,怎样租到合适的日租房呢?小编就带大家介绍了解一下附近日租房从哪里找? 附近日租房从哪里找 1、在短租房论坛上。首先可以根据自己的要求选择租房子的具体,然后在短租房的论坛上查看是否有相关的租房信息,选择后可以与房东直接*https://www.qizuang.com/gonglue/jxwd/127816.html
13.大多数游戏租房子在哪儿租大多数租房子位置介绍大多数游戏中,玩家除了可以住酒店还能去租房子,很多小伙伴可能还不清楚在哪租吧,今天小编给大家带来大多数租房子位置介绍,感兴趣的小伙伴快来看一下吧。 租房子位置介绍 游戏中,想要租房子要去第二个酒店旁边的房屋中介所。 这里需要解锁地图才能开启(接到保安职业的任务就解锁地图了)。 到后选择我要租房。 之后https://gl.ali213.net/html/2022-11/953865.html
14.苏州园区哪儿租房划算租房子应当留意什么租房子应当留意什么 1、倘若是单身男女的年青女士要租房得话,那么在租房的情况下一定要考虑到本身的安全隐患,最好不必到较为偏僻的地区和同学一起租房,不必把自己深陷风险当中。 2、租房的情况下,一定要留意开店选址。一般来说城区的房子房租会较为贵,大部分的人都承受不住,而近郊区的房子尽管划算可是又很远,租房https://m.fccs.com/zhishi/85741.html
15.廊坊房屋出租信息在哪看,廊坊市出租房屋房产信息廊坊房屋出租信息在哪看,廊坊市出租房屋 目录一览: 1、消费广场的官方网站 2、廊坊大学城附近租房子大概需要多少钱 3、廊坊都市网网站定义 4、廊坊房屋租赁协议规定要写哪些内容 5、燕郊论坛的介绍 6、燕郊论坛燕郊论坛介绍 消费广场的官方网站 1、消费广场网是河北消费广场广告有限公司旗下的集互联网与平面媒体信息http://www.anjia-365.com/post/288.html