JSK动态代理

内容导航

  • 代理模式 proxy pattern
    • proxy
    • proxy pattern
    • proxy role
    • 静态代理 static proxy
      • 静态代理的缺点
    • dynamic proxy 动态代理
      • 反射 -- Method
      • 动态代理步骤
      • 动态代理实例

Javaweb — 深化一下反射,之后会再看一下线程和并发


java设计模式 — 代理模式: 动态代理jdk实现


JQuery虽然被新的技术取代了,但是通过实例就发现相比原生的JS,JQuery简化了很多;接下来再来看看动态代理— 其实就是之前的反射机制,J2EE中使用过多次了,这里正式来康康

动态代理 — 基于反射机制的;之前使用过多次反射,尤其是几个工具类,第一个就是DBUtil使用了简单的forname方式进行类加载;之后再JSONUtil中使用了Class和Field;和方法一样设置可以access变可获取私有的属性,正常的情况下是获取不到的

代理模式 proxy pattern

proxy

代理就比如中介一样,帮助去实现某些操作,也就是允许客户端通过这个服务与另外一个end system进行非直接的服务,所以说路由器等就相当于是一个代理

从中介来分析: 比如房产中介,中介和代理所做的事情都是一致的,那就是招揽客人; 中介是房源的代理,房源是目标;这个过程就是 【客户 -----> 中介 ------> 房源】,中介是代理,会收费的;尽管如此,还是有很多中介存在;因为中介是专业的、非常的方便;其次就是客户不能独自找到房源,或者找房源十分困难

在实际开发中,也就有了代理的情况,也就是对客户----代理 ---- 目标链式关系的抽象,比如有一个类A,还有一个类C,如果A类的功能需要调用C类,但是C类不允许A调用,所以这个时候可以找一个代理类B,B访问C;A再访问B即可,完成功能 【比如项目的短信验证码的功能,项目是不可能直接发送短信的,短信只有电信运营商才能发送,所以找一个中介关联公司 项目 ------------- 关联公司、中介 ------ 中国移动、电信、联通】

proxy pattern

为其他对象提供一种代理可以控制对这个对象的访问,在某些情况下,一个对象不舍和或者不能直接引用另一个对象,而代理对象可以在客户类和目标对象之间起到中介的作用。使用代理模式,是为了在不修改目标对象的基础上,增强业务逻辑,客户类对目标对象的访问时通过访问代理对象来实现

proxy role

上面介绍了代理模式,那么其作用是什么呢?

  1. 功能增强、易于扩展 --------- 原来比如new Dao(),那么如果使用代理类来执行这个操作,在代理类中所写的其他的代码就是属于功能增强;但是这并没有修改原来的代码【符合开闭原则】
  2. 控制访问,保护对象 ------ 目标类不让客户类直接访问,这样可以对目标类起到保护的作用
  3. 使职责更加明确 ----- 比如在service中应该全部都是业务逻辑,而创建对象不属于业务逻辑,使用代理可以明确分工

代理模式分为静态代理和动态代理,二者的不同?

静态代理 static proxy

  1. 代理类是自己手工实现,自己创建一个java类,来表示代理类
  2. 代理的目标类是确定的
  3. 实现很简单,容易理解

这里来做一个例子来模拟一下代理,比如现在抽象一个关系链条 : 用户到商家位置买雪糕; 商家的雪糕从厂家进的;现在用户想要购买雪糕,实现功能【不能直接从厂家拿雪糕】,那么实现这个功能: 首先需要创建一个接口,定义卖雪糕的方法,展示商家和厂家的做的事情;其次创建厂家和商家类都要实现接口,最后创建客户类,调用商家的方法买一个雪糕

通过代理模式才能进行功能增强,也就是扩展功能;对扩展开发,对修改关闭

package cfeng.proxy;//表示功能,厂家和商家都要实现这个方法
public interface IcecreamSell {//定义方法,售卖雪糕param表示单价float sell(int amount);//可以定义其他的方法
}

这里就是接口,商家和厂家都会实现这个接口

package cfeng.proxy;public class CfengFactory implements IcecreamSell {//厂家不支持用户的单独购买@Overridepublic float sell(int amount) {//简单return即可return 85.0f;}}

厂家继承了接口,对接口进行了继承,完成了雪糕的销售

package cfeng.proxy;public class Merchant implements IcecreamSell {//声明商家所代理的生产雪糕厂家private IcecreamSell factory = new CfengFactory();@Overridepublic float sell(int amount) {//向厂家调用订单,告诉厂家,让其发货float pri = factory.sell(amount);//商家作为中间商需要加价pri += 25;  //这部分代码就是属于功能增强,因为原来只会有上面的代码,这里都是额外的,易于扩展//返回给用户价格return pri;}
}

商家也实现了接口,这里商家完成了两件事情,第一件事情就是调用厂家的方法,第二件事就是进行加价;加价这部分【除了原来的方法的调用之外】,都是属于功能的增强的部分

package cfeng.proxy;public class Client {//从商家购买雪糕;不能直接从public static void main(String[] args) {Merchant mercha = new Merchant();System.out.println(mercha.sell(1));}
}

最后就是客户类,客户通过调用商家【代理】的【增强之后的】方法,完成了业务;这里的代理可以有多个,因为可以有多个商家,它们所做的处理不同;所以不同的代理可以完成不同的扩展

因此: 代理的最主要的功能就是 : 目标类的方法的调用【代理是没有直接的目标的功能的】, 功能的增强

静态代理的缺点

  • 静态代理的目标固定,所以如果有很多目标,那就需要很多个代理,这样代码冗杂了

  • 当接口中功能增加了,或者修改了,因为众多的代理实现类,那么修改的工作量大,这样就容易出现问题

dynamic proxy 动态代理

在程序的执行过程中,创建代理对象,动态指定代理目标类;动态代理就是一种创建对象能力,不用创建类,就可以获得对象 ------ 就是反射机制,获得类的字节码,再invoke即可; 动态代理是指代理类对象在程序运行时有JVM根据根舍机制动态生成的,动态代理不需要定义代理类的java源文件,动态获取类,(比如通过对象,通过完整的类名) 动态创建class字节码加载到JVM

动态代理的方式:

  • JDK 动态代理: 使用java反射包中的类和接口实现动态代理的功能 反射包java.lang.reflect : 其中的三个类Method,InvocationHandler、Proxy
  • cglib动态代理 : cglib时第三方工具库,创建代理对象,cglib的原理就是继承,通过继承目标类,创建其子类,在子类中重写超类的方法,实现功能的修改 — 所以父类不能是final的;cglib在很多框架中使用【比如mybatis、springAOP就会使用

反射 – Method

之前分享反射的时候着重分享了几个类,首先就是Class类,承载的是类的字节码;之后还有Method类表示的是类中的方法【公私均可】,Field类表示的是类的属性【公私均可】; 但是私有的一定要设置可访问,setAccess;这是之前最经常使用的

这里可以用反射的方式实现之前的客户类

public class Client {//从商家购买雪糕;不能直接从public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {/*Merchant mercha = new Merchant();System.out.println(mercha.sell(1));*///这里不通过创建对象的方式,如何得到上面的结果?反射即可 --- 使用Method//获取类的字节码  try {Class cls = Class.forName("cfeng.proxy.Merchant");//通过字节码创建一个对象;通过构造方法创建Object obj = cls.getDeclaredConstructor().newInstance();//通过类的字节码获取到所有的方法Method method = cls.getDeclaredMethod("sell",int.class);//执行该方法通过method的invoke方法;第一个参数是对象,第二个是方法执行时的参数值 方法执行后的返回值Object o = method.invoke(obj, 1);//o就是函数的返回值System.out.println(o);} catch (ClassNotFoundException e) {e.printStackTrace();}}
}
  • 这里通过类的字节码创建对象,不能直接使用newInstance了,since version 9就过时了,需要先获得构造器,之后再创建对象;
  • 获得类的方法可以通过Class的getDeclaredMethod方法,第一个参数时方法的名称,第二个参数是方法的参数的字节码;
  • 执行方法通过Method的invoke方法,这个方法的第一个参数为该类的一个具体的对象,第二个参数是该方法传入的具体的参数的值;返回值为方法的返回值【invoke 调用】

动态代理步骤

动态代理的目标不是固定的,根据代理的对象,动态创建代理类,这样就避免了静态代理中的类过多的问题,动态代理的实现方式---- 反射; 可以直接使用java.lang.reflect.Proxy; 动态代理的实现步骤如下

jdk动态代理要求目标对象必须要实现接口,没有接口就实现不了动态代理

  1. 编写一个委托类、目标类的接口【定义目标类要完成的功能】
  2. 实现一个真正的委托类【编写目标类】
  3. 创建InvocationHandler接口的实现类,重写invoke方法,完成代理类的功能—调用目标方法、增强功能
  4. 使用Proxy类的newProxyInstance()静态方法生成动态代理的对象 ,并将返回值转为接口类型

动态代理主要依托的reflect包中的三个类: invocationHandler、Method、Proxy

  • invocationHandler【调用处理器】 接口 ------- 就是表明代理要做什么: 这是一个函数式接口,其中就一个方法invoke;invoke方法表示代理对象要执行的功能代码;代理类要完成的功能就卸载invoke代码中【目标方法的调用、功能增强】
 public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
Object proxy : 这是jdk创建的代理对象,无需赋值
Method  method : 目标类中的方法,jdk提供method ---->这里的method代指的就是目标方法
Object[] args : 目标类中方法的参数   -----> 所以说如果有多个参数,就写成一个集合即可 --->目标方法的参数 {int.class,String.class,……}
  • Method类: 表示方法的,也就是通过Method可以执行某个目标类的方法,通过invoke方法执行目标的方法

  • Proxy类: 核心的对象,用于创建代理对象,之前创建对象都是new 类构造方法;现在可以直接使用Proxy类的方法,代替new的使用

静态方法 ---- newProxyInstance()方法
作用就是创建代理对象,等同于静态代理的new ……

这里可以看一下源码

    @CallerSensitivepublic static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) {Objects.requireNonNull(h);final Class<?> caller = System.getSecurityManager() == null? null: Reflection.getCallerClass();Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);return newProxyInstance(caller, cons, h);}ClassLoader loader : 类加载器,负责向内存中加载对象 --- 使用反射机制就可以获得对象的classLoader ----比如对于类String ---》String.class.getClassLoader()  也就是获得目标的类Class<?>[] interfaces  接口,目标对象实现的接口,也是通过反射获取的InvocationHandler h :也就是之前实现的InvocationHandler接口,完成代理类的功能

通过Proxy类的这个newProxyInstance方法就可以生成一个目标对象的代理对象

动态代理实例

这里就不另外编写例子了,就以刚刚静态代理的买雪糕的例子 ---- 用户不能直接从从某一个具体的工厂买雪糕,那么就需要创建一个代理类商家来进行间接购买,同时商家增强了功能【抬价】 所以这里的核心应该是用户和目标;商家是为了处理这个业务应运而生的类型

按照动态代理的固定步骤,首先要规范目标类【服务类】的行为,面向接口编程,定义一个接口 ----- 定义接口的目的就是因为,客户类想使用的其实就是该接口定义的方法,所以真正要代理的是方法,而不是某一个具体实现类;多态的核心就是抽象,这样就便于扩展而少修改

package cfeng.proxy;//表示功能,厂家和商家都要实现这个方法
public interface IcecreamSell {//定义方法,售卖雪糕param表示单价float sell(int amount);//可以定义其他的方法
}

这个接口也就是为了完成客户类想要实现的功能;之后定义实现类来实现这个功能接口

package cfeng.proxy;public class CfengFactory implements IcecreamSell {//厂家不支持用户的单独购买@Overridepublic float sell(int amount) {//简单return即可System.out.println("执行服务接口的具体实现类的实现方法");return 85.0f;}}

本来按照静态代理,接下来就要手动去创建针对这个服务类的代理类;但是动态代理接下来就是创建InvocationHandler接口的实现类

这里的参数中,method就代表的是目标方法,args代表的就是目标方法的参数,所以为了执行方法,这里需要执行Method的invoke方法,需要传入目标类型的对象,这里就使用带有参数的构造方法实现传入目标对象

package cfeng.proxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;/*** 完成代理类要执行的功能,这里需要注意的是后两个对象就是目标参数,其实就是接口中的方法---代理方法而不是代理具体的实现类* 通过构造器获得方法执行的具体的对象【多态】*/
public class SellHandler implements InvocationHandler {// sell功能的处理器【代理功能】private Object obj;public SellHandler(Object obj) {super();this.obj = obj;}// 完成代理类执行的功能@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result = null; //目标方法的返回值// 执行目标方法result = method.invoke(obj, args);//进行功能增强if(result != null) {float pri = (float)result;pri += 25;result = pri;}System.out.println("你获得2元优惠");return result;}
}

第四步就是利用Proxy类的静态方法生成代理对象;代理对象的目的也是执行接口中的sell方法,所以类型是接口的类型

package cfeng.proxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class Client {//从商家购买雪糕;不能直接从public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {//创建需要代理的目标对象IcecreamSell fact = new CfengFactory();//创建调用处理器对象InvocationHandler handler = new SellHandler(fact);//创建代理对象  ---- obj.getClass   类.class Class.forName()IcecreamSell proxy = (IcecreamSell)Proxy.newProxyInstance(fact.getClass().getClassLoader(), fact.getClass().getInterfaces() , handler);//通过代理对象执行方法Object o = proxy.sell(1);System.out.println(o);}
}单从这里来看,这里的动态代理就是类似于一种别样的重载,比如sell;给出的代理类还是有接口中的方法;JDK的动态代理必须有接口,Proxy的第二个参数就一定是接口执行服务接口的具体实现类的实现方法      执行目标接口实现类的功能方法
你获得2元优惠                      执行代理对象的功能增强代码
110.0                        执行代理对象的功能增强代码

只能说动态代理和JDBC一样固化,非常明确的几个步骤

首先就是编写功能接口,【多态】实现接口;

之后就是实现invocationHandler接口来封装代理的功能 — 调用原方法、功能增强 ---- 最后就是使用Proxy的静态方法生成代理对象;这个代理对象就是最开始定义的接口类型的;它的目的还是有这个sell功能 ----- 代理可以在不改变原有的功能的前提下,增加新的功能; 代理类和接口实现类都是接口类型的

动态代理 ---- 框架基础技术相关推荐

  1. 深入理解JDK动态代理原理,使用javassist动手写一个动态代理框架

    文章目录 系列文章索引 一.动手实现一个动态代理框架 1.初识javassist 2.使用javassist实现一个动态代理框架 二.JDK动态代理 1.编码实现 2.基本原理 (1)getProxy ...

  2. 动态代理竟然如此简单!

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 这篇文章我们来聊一下 Java 中的动态代理. 动态代理在 ...

  3. 动态代理之 cglib 实现

    (尊重劳动成果,转载请注明出处:https://blog.csdn.net/qq_25827845/article/details/87513102冷血之心的博客) 目录 前言: 正文: AOP(面向 ...

  4. Java动态代理的两种实现方法

    转载自 http://blog.csdn.net/HEYUTAO007/article/details/49738887 AOP的拦截功能是由java中的动态代理来实现的.说白了,就是在目标类的基础上 ...

  5. Java动态代理和Cglib动态代理最强王者阵容

    Python实战社群 Java实战社群 长按识别下方二维码,按需求添加 扫码关注添加客服 进Python社群▲ 扫码关注添加客服 进Java社群▲ 作者丨黎杜 来源丨非科班的科班(LDCldc1230 ...

  6. 【拿来吧你】JDK动态代理

    java proxy 因为最近一段时间准备将这几年做的一些业务和技术做个沉淀,也自己造的一些轮子,发现时不时就会需要用到动态代理和反射,所以今天打算先对jdk的动态代理这部分内容做个简单的整理 介绍 ...

  7. 微服务乱码_netcore 之动态代理(微服务专题)

    动态代理配合rpc技术调用远程服务,不用关注细节的实现,让程序就像在本地调用以用. 因此动态代理在微服务系统中是不可或缺的一个技术.网上看到大部分案例都是通过反射自己实现,且相当复杂.编写和调试相当不 ...

  8. 让女朋友能懂的网络技术篇之动态代理

    一.前言 笔者在工作经常遇到需要远程访问部署在另外一个城市的服务器上的网站,以分析并解决对方出现的程序异常问题.但是我们部署的程序常常为看不到对方的页面感到困扰,经过一番研究后,终于找到一种切实可行的 ...

  9. mybatis里的日志动态代理

    上一篇博客说到mybatis对日志的实现有一个优先顺序,本篇以jdkLog为例探讨mybatis运用到的动态代理模式. 首先要知道它为什么要使用动态代理,可以观察到当执行mybatis的代码时,他总能 ...

最新文章

  1. 实易智能DNS单台设备QPS高达28万
  2. python程序把文件编码转换
  3. 分布式系统原理 之5 日志技术
  4. DB排行榜更新,.NET Core+MySQL成主流!
  5. 若依单体版本代码生成模块使用教程
  6. UNIX 高级环境编程 第10章 信号
  7. @Autowired与@Resource用法
  8. webView实现网页缩放
  9. python爬虫文字全是乱码_Python爬虫乱码的解决方案!
  10. xshell网站打不开
  11. 计算机在课程中的应用,计算机科学技术在计算机教育中的应用
  12. web前端网页制作思路(只是思路)
  13. shopex mysql索引_shopex数据库表结构说明文档.doc
  14. matlab怎么设置步长,请教matlab中怎么对变步长的数据进行处理
  15. python——文件处理
  16. Unikernels 解读
  17. BZOJ2754: [SCOI2012]喵星球上的点名(AC自动机/后缀自动机)
  18. 通用计算机与嵌入式的比较,嵌入式系统与通用计算机系统相比有什么特点?如题 谢谢了...
  19. Rethink Robotics推出Sawyer智能协作机器人软件开发工具包
  20. 如何策划新闻稿,低成本实现品牌影响力增长

热门文章

  1. Docker--网络详解
  2. java调用R语言传参数时,RserveException: eval failed Syntax error
  3. 计算机专硕考数一英一,专硕难度升级!改考数一英一,这所近2.3万人报考的热门高校大改...
  4. 2021年R1快开门式压力容器操作考试及R1快开门式压力容器操作考试题库
  5. 医保局:医保政策性利好消息!
  6. FCPX插件 66种手绘漫画MG动画元素包 Comic Pop 破解版
  7. C++ 异常 0xC0000005 访问冲突,exit code 0xC0000005 的解决方法
  8. 暴雪每周服务器维护时间,截止至今,暴雪在3.1服务器上进行的紧急更新
  9. loopy()代表什么意思,怎么用
  10. 浅谈MOS管的工作原理