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.房屋一般有哪几种类型员工出国定居,可持护签证、户籍注销证明和国外定居证明办理销户提取;3、员工因故丧失劳动能力,终止劳动关系,可销户提取;4、被宣告死亡,由继承人持相关证明材料办理销户提取; 房产证分几种类型房子的产权包括《房屋所有权证》、《房屋共有权证》、《房屋他项权证》或者《房地产权证》、《房地产共有权证》、《房地产https://lvlin.baidu.com/question/2148468069800296348.html
2.房屋类型分为哪几种文章摘要:随着买房的人越来越多,为了满足人们买房的需求,房屋的类型也是越来越多,那么房屋类型分为哪几种呢? 1、按房子级别分类分为三种,分别为:高端住宅、普通住宅、别墅; 2、按设计特点分为:独栋、联排、花园洋房、双拼、叠拼、空中别墅。 3、按历史发展分类分别有:古典主义建筑风格、现代评论风格、新古典主义建http://www.loupan.com/bk/66105.html
3.哪几种类型的房子不能抵押贷款哪几种类型的房子不能抵押贷款 一、哪几种类型的房子不能抵押贷款 房地产抵押,是指抵押人以其合法的房地产以不转移占有的方式向抵押权人提供债务履行担保的行为。债务人不履行债务时,抵押权人有权依法以抵押的房地产拍卖所得的价款优先受偿。抵押人是指以房地产作为本人或第三人履行债务担保的企业法人、个人和https://m.64365.com/zs/1223611.aspx
4.Java基础知识点总结2.3) 新建Java类---房子 项目(包含)--->包(包含)--->类(包含)--->代码 符合包含关系 , 举什么例子都可以 day02 八大基本类型从小到大:byte, short, int, long, float, double, char, boolean int:整型,4个字节,-21个多亿到21个多亿 Java 1)整数直接量默认为int类型https://blog.csdn.net/weixin_51489166/article/details/118520635
5.房屋户型有哪些类型哪种户型是好户型房屋户型是指住宅的内部空间布局和设计,它影响着居住的舒适度和功能性。那么,房屋户型有哪些类型,哪种户型是好户型呢?今天小编就和大家来聊聊房屋户型,一起往下看吧。 一、房屋户型有哪些类型 1、复式/跃层:有两层或更多层的居住空间,通常上层为卧室,下层为客厅和厨房。 https://m.qizuang.com/gonglue/fangchan/145793.html
6.房地产基础知识大全购房用于过渡性居住,一般对功能、面积的考虑,只要未来3-5年内够住用即可,除此之外,还应考虑未来几年较容易转让变现或较易出租。 53、如何选择贷款方式和确定贷款总额? 答:目前我国住房贷款还款方式有两种,一种是“等额本金还款法”,另一种是“等额本息还款法”。“等额本息还款法”还款本息总额略高于“等额本金https://www.360doc.cn/article/17211243_375449969.html
7.亚马逊cpc广告类型有哪几种,cpc广告如何优化亚马逊cpc广告类型包括3种:1、单品展示广告;2、头条搜索广告;3、付费产品广告。选择做cpc运营推广,跟建一座房子差不多,需要先打好地基,设计好图纸,然后按照规划进行添砖加瓦,最后再去封顶完工。 图片来源:图虫创意 亚马逊cpc广告类型有哪几种: 1、单品展示广告 https://www.cifnews.com/article/136551
8.美国房产的这几种房屋类型,你知道优缺点吗?美国房产的房屋类型与中国相比还是有差别的,美国的房屋主要有这五种类型,分别是独立屋、公寓、多家庭房屋,其中独立屋分为独栋别墅和联排独栋别墅。下面我们一起看看美国房产这五种类型,都有哪些优点和缺点? 独立屋Single Family Home 美国的房屋产权是包括土地及建筑物,这种形态在中国称为别墅。但别墅并不是正确的解https://www.immiknow.com/houus/content/8964.html
9.个人所得税专项附加扣除政策解读综合办公室79.赡养老人专项附加扣除的分摊方式有哪几种? 答:赡养老人专项附加扣除的分摊方式包括由赡养人均摊或约定分摊,也可以由被赡养人指定分摊。采取指定分摊或者约定分摊方式的,每一纳税人分摊的扣除额最高不得超过每月1000元,并签订书面分摊协议。指定分摊与约定分摊不一致的,以指定分摊为准。 https://www.qvc.edu.cn/cjc/col/1600421691329/2023/06/16/1686897794978.html
10.房本那些事原来房产证颜色不同区别这么大!买房时一定要搞清楚而很多朋友在买房子的时候只关注了位置、楼层、户型、价格,对于产权的问题并没有那么上心,售楼处只要说了有产权,可能真就觉得自己买到大产权的房子了。 其实房屋产权所涉及到的问题很多,不是售楼处一句有产权这么简单的。那么,房产证是什么?分哪几种类型呢?下面便跟着八块钱网一起来看看吧! https://www.8kqw.com/?mod=article&code=view&id=19841