目录

一 代理模式

1.1 简介

1.2 代理模式角色定义

二 静态代理

2.1 介绍和实例

2.2 静态代理的缺点

三 动态代理

3.1 基于JDK原生动态代理实现

四 小结


一 代理模式

1.1 简介

Java的动态代理在实践中有着广泛的使用场景,比如最场景的Spring AOP、Java注解的获取、日志、用户鉴权等。

先看百度百科的定义:

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

代理模式解释起来就是,设定指定的“代理人(Proxy代理类)”执行RealSubject类中的具体方法。我们对RealSubject类中的左右操作都通过“代理人(Proxy代理类)调用RealSubject类进行执行。

通过代理模式,我们可以做到两点:

1、隐藏代理类的具体实现(RealSubject类中才是具体实现)。

2、实现客户与代理类的解耦,可以在不改变代理类代码的情况下添加一些额外的功能(日志、权限)等。

1.2 代理模式角色定义

在上述的过程中在编程的过程中我们可以定义为三类对象:

  • Subject(抽象主题角色):一般为接口,定义代理类和真实主题的公共对外方法,也是代理类代理真实主题的方法。比如:出售商品等。
  • RealSubject(真实主题角色):真正实现业务逻辑的类。比如实现了广告、出售等方法的厂家(Factoryer)。
  • Proxy(代理主题角色):用来代理和封装真实主题。比如,同样实现了广告、出售等方法的超时(Shop)。

以上三个角色对应的类图如下:


二 静态代理

2.1 介绍和实例

静态代理是指代理类在程序运行前就已经存在,这种情况下的代理类通常都是我们在Java代码中定义的。

静态代理例子:工厂主(Factoryer)需要执行的工厂(IFactory)的主要function就是卖工厂的货(sell方法),我们现在需要委托商店(shop)这个代理来代卖货物。顾客也就是client是通过商店shop这个代理买东西的。

IFactory接口定义如下:

/*** Subject 接口* IFactory 定义了要做的事情,就是卖东西,但是工厂是委托给商店代卖的* 委托类和代理类都实现了IFactory接口**/
public interface IFactory { /** 出售 */void sell();}

Vendor类定义如下

/*** RealSubject类* 真实主题类,是客户端通过代理类间接调用的  真正实现具体需要实现方法的主体。* 工厂主,他要卖东西,他是Factory这个抽象主体的具体实现,他要卖东西**/
public class Factoryer implements IFactory{@Overridepublic void sell() {System.out.println("出售货物");}}

Shop类定义如下:

/*** Proxy代理类* 超市,代理卖东西**/
public class Shop implements IFactory{private Factoryer factoryer;public Shop(Factoryer factoryer){this.factoryer = factoryer;}@Overridepublic void sell() {System.out.println("Shop是商店代理,用于直接对接client顾客,执行sell方法");factoryer.sell();}
}

其中代理类Shop通过聚合的方式持有了被代理类Factoryer的引用,并在对应的方法中调用Factoryer对应的方法。

下面看看在客户端中如何使用代理类,即客人怎么通过这套代理体系买东西。

public class ClientBuy {public static void main(String[] args) {// 被代理类Factoryer factoryer = new Factoryer();// 创建供应商(也就是真正执行卖东西这个方法操作的factoryer)的代理类ShopIFactoryer ifactoryer = new Shop(factoryer);// 客人买东西时面向的是代理类Shop。ifactoryer.sell();}
}

在上述代码中,我们可以在Shop中修改或新增一些内容,而不影响被代理类Factoryer 。比如我们可以在Shop类中新增一些额外的处理,类似于筛选购买用户、记录日志等操作。

2.2 静态代理的缺点

静态代理实现简单且不侵入原代码,但当场景复杂时,静态代理会有以下缺点:

1、当需要代理多个类时,代理对象要实现与目标对象一致的接口。我们只有两个选择,1:只维护一个代理类来实现多个接口,但这样会导致代理类过于庞大;2:新建多个代理类,但这样会产生过多的代理类。

2、当接口(IFactoryer)需要增加、删除、修改方法时,目标对象(ClientBuy)与代理类(shop)都要同时修改,不易维护。

于是,动态代理便派上用场了。


三 动态代理

动态代理是指代理类在程序运行时进行创建的代理方式。这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据Java代码中的“指示”动态生成的。

相比于静态代理,动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。

3.1 基于JDK原生动态代理实现

实现动态代理通常有两种方式:JDK原生动态代理和CGLIB动态代理。这里,我们以JDK原生动态代理为例来进行讲解。

JDK动态代理主要涉及两个类:java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler。

InvocationHandler接口定义了如下方法:

/*** 调用处理程序*/
public interface InvocationHandler { Object invoke(Object proxy, Method method, Object[] args);
}

顾名思义,实现了该接口的中介类用做“调用处理器”。当调用代理类对象的方法时,这个“调用”会转送到invoke方法中。动态代理中,Proxy 动态产生的代理会调用 InvocationHandler 实现类,所以 InvocationHandler 是实际执行者

InvocationHandler方法的,第一个参数proxy参数为代理类对象,第二个参数为method,表示具体调用的是代理类的哪个方法,第三个参数args为为第二个参数该方法的参数。

这样对代理类中的所有方法的调用都会变为对invoke的调用,可以在invoke方法中添加统一的处理逻辑(也可以根据method参数对不同的代理类方法做不同的处理)。

下面以添加日志为例来演示一下动态代理。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Date;public class LogHandler implements InvocationHandler {Object target;  // 被代理的对象,实际的方法执行者public LogHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {before();Object result = method.invoke(target, args);  // 调用 target 的 method 方法after();return result;  // 返回方法的执行结果}// 调用invoke方法之前执行private void before() {System.out.println("调用方法sell之前的日志处理");}// 调用invoke方法之后执行private void after() {System.out.println("调用方法sell之后的日志处理");}
}

客户端编写程序使用动态代理代码如下:

import java.lang.reflect.Proxy;
/*** 动态代理测试** @author sec* @version 1.0* @date 2020/3/21 10:40 AM**/
public class DynamicClientBuy {public static void main(String[] args) {// 创建中介类实例LogHandler logHandler = new LogHandler(new Factoryer());// 获取代理类实例IFactoryIFactory iFactory = (IFactory) (Proxy.newProxyInstance(IFactory.class.getClassLoader(), new Class[]{IFactory.class}, logHandler));// 通过代理类对象调用代理类方法,实际上会转到invoke方法调用iFactory.sell();}
}

Proxy.newProxyInstance的三个参数含义为:

  • loader 自然是类加载器
  • interfaces 代码要用来代理的接口
  • h 一个 InvocationHandler 对象

执行之后,打印日志如下:

调用方法sell之前的日志处理
Shop sell goods
调用方法sell之后的日志处理

经过上述验证,我们发现已经成功为我们的被代理类统一添加了执行方法之前和执行方法之后的日志。


四 小结

了解代理模式可以让我们的系统设计的更加具有可扩展性。而动态代理的应用就更广了,各类框架及业务场景都在使用。

Java动态代理的优势是实现无侵入式的代码扩展,也就是方法的增强:不改变这个方法的前提下去丰富它;你可以在不用修改源码的情况下,增强一些方法;在方法的前后你可以做你任何想做的事情(甚至不去执行这个方法就可以)。老功能用原来的方法不会有问题,新功能通过代理丰富了原来的方法也能被广泛试用。

动态代理类:在程序运行时,通过反射机制动态生成。
动态代理类通常代理接口下的所有类。
动态代理事先不知道要代理的是什么,只有在运行的时候才能确定。
动态代理的调用处理程序必须事先InvocationHandler接口,及使用Proxy类中的newProxyInstance方法动态的创建代理类。
Java动态代理只能代理接口,要代理类需要使用第三方的CGLIB等类库

掌握到这里其实已经差不多了,关于更多一些例子包括源码的一些分析,可以看我的参考文章。

参考:

Java代理模式及动态代理详解 - 程序新视界

从代理模式再出发!Proxy.newProxyInstance的秘密_葵续浅笑的博客-CSDN博客_proxy.newinstance

Java动态代理的作用及好处_明洋的专栏-CSDN博客_动态代理的作用

详解java动态代理机制以及使用场景(一)_远方和诗 的博客-CSDN博客_动态代理使用场景

轻松学,Java 中的代理模式及动态代理_frank 的专栏-CSDN博客_动态代理和代理模式

Java内功修炼系列:代理模式及动态代理相关推荐

  1. Java篇 - 代理模式和动态代理实现原理

    设计模式中有一种模式叫代理模式,Spring框架离不开动态代理技术,Android hook技术用到了反射 + 动态代理,Framework中我们也经常看到各种proxy,如ApplicationTh ...

  2. Java拾遗:007 - 代理模式与动态代理

    2019独角兽企业重金招聘Python工程师标准>>> 代理模式 在日常开发中我们可以会接手一些老的项目,有时连源码都没有,或者有时候我会需要对业务逻辑做一定增强(功能扩展,如:日志 ...

  3. 代理模式、动态代理和面向方面

    代理的意思很好理解,它借鉴了我们日常所用的代理的意思:就是本来该自己亲自去做的某件事,由于某种原因不能直接做,而只能请人代替你做,这个被你请来做事的人就是代理.比如过春节要回家,由于你要上班,没时间去 ...

  4. 代理模式和动态代理模式_代理模式介绍

    代理模式和动态代理模式 代表:被选中或当选为他人投票或代理的人– Merriam-Webster . 委托模式:在软件工程中,委托模式是面向对象编程中的一种设计模式,其中,一个对象而不是执行其陈述的任 ...

  5. 【设计模式】--- 装饰器模式、静态代理模式和动态代理模式

    文章目录 1 引子 2 业务场景介绍 3 静态代理模式 4 装饰器模式 5 动态代理模式 5.1 Proxy --- 具体的代理对象生成组件 5.2 InvocationHandler --- 封装被 ...

  6. 20171030_chr_proxy 代理模式(动态代理)

    代理模式(动态代理) /20171030_chr_proxy/src/nuc/sw/dynamic/proxy/Dog.java package nuc.sw.dynamic.proxy;public ...

  7. 设计模式—代理模式以及动态代理的实现

    代理模式(Proxy Design Pattern)是为一个对象提供一个替身,以控制对这个对象的访问.即通过代理对象访问目标对象.被代理的对象可以是远程对象.创建开销大的对象或需要安全控制的对象. 一 ...

  8. Java内功修炼系列一责任链模式

    在上一节的拦截器中提到,程序的设计者一般会用拦截器替替代动态代理,将动态代理的逻辑隐藏起来,而把拦截器接口提供给开发者,使开发者不需要关系动态代理的具体实现过程,但是有时候需要多个拦截器,而且拦截器之 ...

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

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

最新文章

  1. hadoop+spark生态系统操作与指南非影印版_Spark背景知识学习
  2. Python安装Jupyter Notebook配置使用教程
  3. python mongodb 异步_Python异步读写Mongodb(motor+asyncio)
  4. 【DP】LeetCode 64. Minimum Path Sum
  5. 使用 TensorFlow 做文本情感分析
  6. SwiftyJSON 对网络请求来的数据进行解析或者转为modul
  7. iTunes恢复系统显示正在等待iPhone解决步骤
  8. 计算机主机内部的结构,台式电脑主机内部结构介绍
  9. 带你搞懂朴素贝叶斯分类算法
  10. Android视频播放器开发
  11. Maestro 薛定谔软件简单分子对接案例
  12. 光遇为什么显示服务器连接错误,光遇服务器错误怎么办 光遇服务器错误问题解决办法-游侠手游...
  13. PEPC丨磷酸烯醇丙酮酸羧化酶应用实例展示
  14. GPT-3有多强?伯克利小哥拿它写“鸡汤”狂涨粉,还成了Hacker News最火文章?!
  15. 贝宁ECTN/BESC认证相关规定
  16. delphi多线程加锁
  17. 精华贴子整理之SQL性能优化2
  18. 2022年全球与中国辐射屏蔽墙行业产销需求与投资预测分析报告
  19. 本机DNS服务器地址查询
  20. 刘金藏:3.24黄金晚间如何操作3.25黄金原油最新操作策略

热门文章

  1. 计算机上指数函数的表示方法,归一化指数函数
  2. 点击 数字随着变化html,js数字随着其他数字变化而变化?
  3. 虚拟化服务器centos7,centos7看服务器开了虚拟化(centos虚拟化kvm)
  4. top,ps,pstree工具介绍及举例
  5. 荣耀3手机android 5.0吗,华为荣耀3的手机系统是什么?华为荣耀3能升级安卓4.3吗?...
  6. 《童梦奇缘-梦幻般的羁绊》第六章-残月
  7. 小鲨鱼在51nod小学
  8. vue 的computed和watch在什么时候触发
  9. 树莓派:10行代码体验红外检测
  10. vue-amap 高德地图定位 点击获取经纬度和具体地址的使用