前言

只有光头才能变强

回顾前面:

  • ThreadLocal就是这么简单
  • 多线程三分钟就可以入个门了!
  • 多线程基础必要知识点!看了学习多线程事半功倍
  • Java锁机制了解一下
  • AQS简简单单过一遍
  • Lock锁子类了解一下
  • 线程池你真不来了解一下吗?
  • 多线程之死锁就是这么简单

多线程就先告一段落了,昨天写完多线程,本来打算是看IO的知识点的,后来看了一下IO的几种模型,又翻了一下《Java编程思想》。不知道从哪下手~~

在看到FilterInputStreamFilterOutputStream时看到了之前常听见的装饰模式(对IO一定了解的同学可能都会知道那么一句话:在IO用得最多的就是装饰模式了)!

看到这里你以为我要讲装饰模式了么?不是,今天我们来讲讲什么是代理模式(就是这么皮,装饰模式明天讲吧~)。

受知乎@Beautiful Java文章和《设计模式之禅》的启发,我也来搞一篇脑洞小开的文章..

由标题可知,这篇文章是写给我女朋友看的。自从她知道我开了公众号以后就每天看我写的文章,之前写点小算法的时候她觉得编程还是挺有意思,想去学学。可是,从我开始写Java容器、多线程,她说一点都看不懂了。于是乎,现在来写点既高大尚、又容易懂的东西

GirlFriend girlFriend = new GirlFriend();sayingProxy(girlFriend);

那么接下来就开始吧,如果文章有错误的地方请大家多多包涵,不吝在评论区指正哦~

声明:本文使用JDK1.8

一、代理模式介绍

代理模式是一种非常好理解的一种设计模式,生活中处处都有代理

  • 王宝强作为一个明星,不可能什么事都由他自己干(约电视剧、排期之类的),于是他请了经纪人
  • 去医院挂号很麻烦怎么办?找黄牛帮我们挂号
  • 王者荣耀技术水平不够,想要上分怎么办?请游戏代练
  • 写点不正经的代码被警察捉走了怎么办?请律师帮我们打官司

无论是经纪人、黄牛、游戏代练、律师他们都是得帮我们干活。但是他们不能一手包办的,仅仅在“我”的基础上处理一些杂碎的东西(我们不愿意干、或者干不了的东西)。

  • 导演找了黄宝强的经纪人让王宝强去拍电影
  • 黄牛去排队让我们能挂上号
  • 游戏代练上分是我的微信账号
  • 律师帮我处理法律上的问题,如果打官司失败,牢还是由我来坐

再举个例子:

  • 现在我是一个网红,拥有很多粉丝。粉丝希望我天天写代码给他们看,那我肯定不能天天写代码啊,我岂不是很忙....于是乎,我就去找了个经纪人。这个经纪人就代表了我。当忠实粉丝想要我写代码的时候,应该是先找经纪人,告诉经纪人想让我写代码。
  • 十年过去了,我越来越红了,头发也越来越少。不是粉丝想要我写代码,我就写了。我要收费了。但是呢,作为一个公众人物,不可能是我自己说:我要收10000万,我才会去写代码。于是这就让经纪人对粉丝说:只有10000万,我才会写代码。
  • 无论外界是想要我干什么,都要经过我的经纪人。我的经纪人也会在其中考虑收费、推脱它们的请求。
  • 经纪人就是代理,实际写代码的还是我

所以说代理模式就是:当前对象不愿意干的,没法干的东西委托给别的对象来做,我只要做好本分的东西就好了!

二、用代码描述代理模式(静态代理)

这里有一个程序员接口,他们每天就是写代码

public interface Programmer {// 程序员每天都写代码void coding();}

Java3y也是一个程序员,他也写代码(每个程序员写的代码都不一样,所以分了接口和实现类)


public class Java3y implements Programmer {@Overridepublic void coding() {System.out.println("Java3y最新文章:......给女朋友讲解什么是代理模式.......");}
}

此时Java3y已经是一个网红了,他不想枯燥地写代码。他在想:“在写代码时能赚钱就好咯,有人给我钱,我才写代码”。但是,Java3y的文笔太烂了,一旦有什么冬瓜豆腐,分分钟变成过气网红,这是Java3y不愿意看到的。

而知乎、博客园这种平台又不能自己给自己点赞来吸引流量(-->当前对象无法做)

所以Java3y去请了一个程序员大V(代理)来实现自己的计划,这个程序员大V会每次让Java3y发文章时,就给Java3y点赞、评论、鼓吹这文章好。只要流量有了,钱就到手了。


public class ProgrammerBigV implements Programmer {// 指定程序员大V要让谁发文章(先发文章、后点赞)private Java3y java3y ;public ProgrammerBigV(Java3y java3y) {this.java3y = java3y;}// 程序员大V点赞评论收藏转发public void upvote() {System.out.println("程序员大V点赞评论收藏转发!");}@Overridepublic void coding() {// 让Java3y发文章java3y.coding();// 程序员大V点赞评论收藏转发!upvote();}
}

文章(代码)还是由Java3y来发,但每次发送之后程序员大V都会点赞。


public class Main {public static void main(String[] args) {// 想要发达的Java3yJava3y java3y = new Java3y();// 受委托程序员大VProgrammer programmer = new ProgrammerBigV(java3y);// 受委托程序员大V让Java3y发文章,大V(自己)来点赞programmer.coding();}
}

这样一来,不明真相的路人就觉得Java3y是真厉害,知识付费。

2.1透明代理(普通代理)

经过一段时间,Java3y尝到甜头了,觉得这是一条财路。于是Java3y给足了程序员大V钱,让程序员大V只做他的生意,不能做其他人的生意(断了其他人的财路)。

于是乎,程序员大V做Java3y一个人的生意:


public class ProgrammerBigV implements Programmer {// 指定程序员大V要给Java3y点赞private Java3y java3y ;// 只做Java3y的生意了public ProgrammerBigV() {this.java3y = new Java3y();}// 程序员大V点赞评论收藏转发public void upvote() {System.out.println("程序员大V点赞评论收藏转发!");}@Overridepublic void coding() {// 让Java3y发文章了java3y.coding();// 程序员大V点赞评论收藏转发!upvote();}
}

于是乎,程序员大V想要赚点零花钱的时候直接让Java3y发文章就好了。


public class Main {public static void main(String[] args) {// 受委托程序员大VProgrammer programmer = new ProgrammerBigV();// 受委托程序员大V让Java3y发文章,大V来点赞programmer.coding();}
}

此时,真实对象(Java3y)对外界来说是透明的

2.2代理类自定义方法

程序员大V看到Java3y一直顺风顺水,赚大钱了。觉得是时候要加价了,于是在点赞完毕后就跟Java3y说每点完一次赞加100块

于是乎,程序员大V就增添了另外一个方法:addMoney()


public class ProgrammerBigV implements Programmer {// ..省略了上面的代码// 加价啦public void addMoney() {System.out.println("这次我要加100块");}@Overridepublic void coding() {// 让Java3y发文章了java3y.coding();// 程序员大V点赞评论收藏转发!upvote();// 加价addMoney();}
}

于是乎程序员大V每次都能多100块:

三、动态代理

几年时间过去了,Java3y靠着程序员的大V点赞还是没发财(本质上Java3y还没有干货,没受到大众的认可)。此时已经有很多人晋升成了程序员大V了,但是之前的那个程序员大V还是一直累加着钱...虽然在开始的时候Java3y尝到了甜头,但现在Java3y财政已经匮乏了。

Java3y将自己的失败认为:一定是那个程序员大V转门为我点赞被识破了,吃瓜群众都知道了,他收费又那么贵。

于是Java3y不请程序员大V了,请水军来点赞(水军便宜,只要能点赞就行了):

public class Main {public static void main(String[] args1) {// Java3y请水军Java3y java3y = new Java3y();Programmer programmerWaterArmy = (Programmer) Proxy.newProxyInstance(java3y.getClass().getClassLoader(), java3y.getClass().getInterfaces(), (proxy, method, args) -> {// 如果是调用coding方法,那么水军就要点赞了if (method.getName().equals("coding")) {method.invoke(java3y, args);System.out.println("我是水军,我来点赞了!");} else {// 如果不是调用coding方法,那么调用原对象的方法return method.invoke(java3y, args);}return null;});// 每当Java3y写完文章,水军都会点赞programmerWaterArmy.coding();}}

每当Java3y发文章的时候,水军都会点赞。

Java3y感叹:请水军真是方便啊~

3.1动态代理调用过程

我们来看看究竟是怎么请水军的:

Java提供了一个Proxy类,调用它的newInstance方法可以生成某个对象的代理对象,该方法需要三个参数:

  • 参数一:生成代理对象使用哪个类装载器【一般我们使用的是被代理类的装载器】
  • 参数二:生成哪个对象的代理对象,通过接口指定【指定要被代理类的接口】
  • 参数三:生成的代理对象的方法里干什么事【实现handler接口,我们想怎么实现就怎么实现】

在编写动态代理之前,要明确几个概念:

  • 代理对象拥有目标对象相同的方法【因为参数二指定了对象的接口,代理对象会实现接口的所有方法】
  • 用户调用代理对象的什么方法,都是在调用处理器的invoke方法。【被拦截】
  • 使用JDK动态代理必须要有接口【参数二需要接口】

上面也说了:代理对象会实现接口的所有方法,这些实现的方法交由我们的handler来处理!

  • 所有通过动态代理实现的方法全部通过invoke()调用

所以动态代理调用过程是这样子的:

3.2静态代理和动态代理的区别

很明显的是:

  • 静态代理需要自己写代理类-->代理类需要实现与目标对象相同的接口
  • 而动态代理不需要自己编写代理类--->(是动态生成的)

使用静态代理时:

  • 如果目标对象的接口有很多方法的话,那我们还是得一一实现,这样就会比较麻烦

使用动态代理时:

  • 代理对象的生成,是利用JDKAPI,动态地在内存中构建代理对象(需要我们指定创建 代理对象/目标对象 实现的接口的类型),并且会默认实现接口的全部方法

四、典型应用

我们之前写中文过滤器的时候,需要使用包装设计模式来设计一个request类。如果不是Servlet提供了实现类给我们,我们使用包装设计模式会比较麻烦

现在我们学习了动态代理了,动态代理就是拦截直接访问对象,可以给对象进行增强的一项技能

4.1中文过滤器

public void doFilter(final ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {final HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse response = (HttpServletResponse) resp;response.setContentType("text/html;charset=UTF-8");request.setCharacterEncoding("UTF-8");//放出去的是代理对象chain.doFilter((ServletRequest) Proxy.newProxyInstance(CharacterEncodingFilter.class.getClassLoader(), request.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//判断是不是getParameter方法if (!method.getName().equals("getParameter")) {//不是就使用request调用return method.invoke(request, args);}//判断是否是get类型的if (!request.getMethod().equalsIgnoreCase("get")) {return method.invoke(request, args);}//执行到这里,只能是get类型的getParameter方法了。String value = (String) method.invoke(request, args);if (value == null) {return null;}return new String(value.getBytes("ISO8859-1"), "UTF-8");}}), response);}

五、总结

第一次以这种方式写文章,举的例子可能会不妥,希望大家见谅~

本文主要讲解了代理模式的几个要点,其实还有一些细节的:比如“强制代理”(只能通过被代理对象找到代理对象,不能绕过代理对象直接访问被代理对象)。只是用得比较少,我就不说了~~

要实现动态代理必须要有接口的,动态代理是基于接口来代理的(实现接口的所有方法),如果没有接口的话我们可以考虑cglib代理。

cglib代理也叫子类代理,从内存中构建出一个子类来扩展目标对象的功能

这里我就不再贴出代码来了,因为cglib的代理教程也很多,与动态代理实现差不多~~~

总的来说:代理模式是我们写代码中用得很多的一种模式了,Spring的AOP底层其实就是动态代理来实现的-->面向切面编程。具体可参考我之前写的那篇文章:

  • Spring【AOP模块】就这么简单

其实只要记住一点:原有的对象需要额外的功能,想想动态代理这项技术

参考资料:

  • 《设计模式之禅》
  • https://wangjingxin.top/2016/11/16/proxy/
  • https://www.cnblogs.com/doucheyard/p/5737366.html

如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y。为了大家方便,刚新建了一下qq群:742919422,大家也可以去交流交流。谢谢支持了!希望能多介绍给其他有需要的朋友

文章的目录导航

  • https://zhongfucheng.bitcron.com/post/shou-ji/wen-zhang-dao-hang

更多的文章可往:文章的目录导航

给女朋友讲解什么是代理模式相关推荐

  1. 设计模式:代理模式是什么,Spring AOP还和它有关系?

    接着学习设计模式系列,今天讲解的是代理模式. 定义 什么是代理模式? 代理模式,也叫委托模式,其定义是给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用.它包含了三个角色: Subject: ...

  2. 代理模式:先生需要代购吗?

    "代理"这个词这几年可谓是家喻户晓了,对于"代理模式"我们也可以通过代购的逻辑来进行理解. 本期干货文章,我们来聊聊编程中GOF23种经典模式之一的" ...

  3. 用另一种方式来讲解代理模式~

    说起代理模式,我算是对他三进三出了,文章至少写的有两篇了,但是我再去看的时候,总感觉不太容易理解,今天来一个我自己的真实案例,通过暑假实习找房子的经历来进行讲解代理模式. 静态代理 代理模式的话,大致 ...

  4. 通俗易懂的讲解一下Java的代理模式

    一.基本概念 代理模式是对象的结构模式. 代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用(接口的引用) 二.静态代理 静态代理是指,代理类在程序运行前就已经定义好,其与**目标类 ...

  5. 深入浅出讲解代理模式(静态代理+动态代理)

    代理模式概述 代理模式定义 #代理模式,即为目标对象提供了一种机制,用于控制对目标对象的访问在某些情况下,一个对象不适合或者不能直接引用某个对象,则可以考虑使用代理对象,代理对象在[客户端]和[目标对 ...

  6. java动态代理_Java代理模式及动态代理详解

    Java的动态代理在实践中有着广泛的使用场景,比如最场景的Spring AOP.Java注解的获取.日志.用户鉴权等.本篇文章带大家了解一下代理模式.静态代理以及基于JDK原生动态代理. 代理模式 无 ...

  7. 设计模式总结——代理模式以及java的动态代理

    定义 给目标对象一个代理对象,并由代理对象控制对目标对象的引用.联想到生活中就像是海外代购 既然是代理,就说明他要做的事情要比你直接去做要做的多,这就联系到了方法的增强,也就联系到了AOP,面向切面. ...

  8. 北风设计模式课程---深入理解[代理模式]原理与技术

    北风设计模式课程---深入理解[代理模式]原理与技术 一.总结 一句话总结: 不仅要通过视频学,还要看别的博客里面的介绍,搜讲解,搜作用,搜实例 设计模式都是对生活的抽象,比如用户获得装备,我可以先装 ...

  9. JAVA设计模式:代理模式

    最近公司从新开发一个项目,为此对老的代码进行评估分析发现有些地方是可以采用代理模式来进行的,为此对代理模式进行了一次理解: 代理模式:即为指定的目标对象提供一个代理商,由代理商来完成对目标对象的操作. ...

  10. 一天一种设计模式之五-----代理模式

    2019独角兽企业重金招聘Python工程师标准>>> 一.代理模式简介 代理模式属于结构型模式 定义:代理模式为其他对象提供一种代理以控制对这个对象的访问. 代理模式是java框架 ...

最新文章

  1. 查看并修改mysql的默认引擎
  2. 《Android艺术开发探索》学习笔记之View的事件体系(一)
  3. BZOJ 1031: [JSOI2007]字符加密Cipher( 后缀数组 )
  4. su切换到oracle后怎么退出,linux下启动oralce和关闭oracle以及数据库实例化
  5. 【Janino】Janino Java表达式计算引擎 案例
  6. java编程算法出现在窗口_Java实现轨迹压缩算法开放窗口代码编程实例分享
  7. 11-8 热点key的重建优化
  8. 2020-01-14 转载【dpdk】使用libpcap-PMD驱动收发包
  9. docker 部署Gitlab
  10. Matlab之通用特殊矩阵函数
  11. 笔记--《谷歌和亚马逊是怎么做产品的》第一至三章
  12. 关于联想键盘,如何去除fn 键 联想官方解决方法
  13. 【源码】用于AD7705的Raspberry Pi Simulink驱动程序
  14. 三星s9刷android9,三星S9港版安卓9rom系统线刷包:TGY-G9600ZHU5CSG8-刷机之家
  15. 蓝桥 字符串跳步 JAVA
  16. php微信绑定银行卡_微信开发企业支付到银行卡PHP
  17. 2014年美国数学建模竞赛C题总结
  18. PSINS惯性系初始对准与代码解读
  19. UML建模、数据库设计和UI设计工具
  20. 单元测试系列之九:Sonar 常用代码规则整理(一)

热门文章

  1. python arp断网攻击_arp断网攻击,手把手教你arp断网攻击怎么解决
  2. twitter、facebook、pinterest、linkedin 分享代码
  3. 移动机器人定位方法概述
  4. JavaScript中的break
  5. phP imageMagic抠图,使用 Lua + ImageMagick 轻松批量抠图
  6. javascript基础常识问答(二)
  7. 薄胶(S18xx,SPR955,BCI-3511,NRD6015)光刻胶
  8. 接入物流快递单号自动识别查询接口API
  9. 吐槽下2014大数据论坛
  10. 数据库无法连接的几种情况