要理解动态代理,需要先理解反射(http://www.cnblogs.com/Donnnnnn/p/7729443.html)

通俗理解:

  1. 在很多底层框架中都会用得到,比如strutsSpring等都用到了动态代理,它的作用很简单:
  1. 利用反射将你要使用的类,重新生成一个子类或本类,这样框架就可以利用这个新生成的类做一些事情,比如在该类的方法前后加一些代码。
  1. 这样的话,你想像一下,你是不是不用修改任何已经编写好的代码,只要使用代理就可以灵活的加入任何东西,将来不喜欢了,不用也不会影响原来的代码。
  2.  

例子:

我们大家都知道微商代理,简单地说就是代替厂家卖商品,厂家“委托”代理为其销售商品。关于微商代理,首先我们从他们那里买东西时通常不知道背后的厂家究竟是谁,也就是说,“委托者”对我们来说是不可见的;

静态代理:

代理类在程序运行前就已经存在(通常都是我们在Java代码中定义的)

代码实例:

厂家: 委托类(被代理类)
微商代理: 代理类

通常情况下,静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类。

下面我们用Vendor类代表生产厂家,BusinessAgent类代表微商代理,来介绍下静态代理的简单实现

委托类和代理类都实现了Sell接口

1、Sell接口的定义如下:

  1. package First;
  2.  
  3. public interface Sell {
  4.  
  5. void sell();
  6.  
  7. void ad();
  8.  
  9. }

2、Vendor类的定义如下:

  1. package First;
  2. /*
  3. * 委托类:厂家
  4. */
  5. public class Vendor implements Sell{
  6.  
  7. @Override
  8. public void sell() {
  9. System.out.println("sell method");
  10. }
  11.  
  12. @Override
  13. public void ad() {
  14. System.out.println("ad method");
  15. }
  16.  
  17. }

3、代理类BusinessAgent的定义如下:

  1. package First;
  2. /*
  3. * 代理类:微商
  4. */
  5. public class BusinessAgent implements Sell {
  6.  
  7. private Vendor vendor;
  8.  
  9. public BusinessAgent(Vendor vendor) {
  10. this.vendor = vendor;
  11. }
  12.  
  13. @Override
  14. public void sell() {
  15. vendor.sell();
  16. }
  17.  
  18. @Override
  19. public void ad() {
  20. vendor.ad();
  21. }
  22.  
  23. }

从BusinessAgent类的定义我们可以了解到,静态代理可以通过聚合来实现,让代理类持有一个委托类的引用即可。

下面我们考虑一下这个需求:

给Vendor类增加一个过滤功能,只卖货给大学生。

通过静态代理,我们无需修改Vendor类的代码就可以实现,只需在BusinessAgent类中的sell方法中添加一个判断方法即可,如下所示:

4、增加功能版BusinessAgent:

  1. package First;
  2. /*
  3. * 代理类:微商
  4. */
  5. public class BusinessAgent implements Sell {
  6.  
  7. private Vendor vendor;
  8.  
  9. public BusinessAgent(Vendor vendor) {
  10. this.vendor = vendor;
  11. }
  12.  
  13. @Override
  14. public void sell() {
  15. if(isCollegeStudent()){
  16. vendor.sell();
  17. }
  18.  
  19. }
  20.  
  21. @Override
  22. public void ad() {
  23. vendor.ad();
  24. }
  25.  
  26. public boolean isCollegeStudent(){
  27. //为了好理解,这里直接返回True
  28. return true;
  29. }
  30.  
  31. }

添加一个判断是否是大学生的方法:isCollegeStudent(),只需在代理类BusinessAgent类中判断,无需修改委托类Vendor

  • 优点一:可以隐藏委托类的实现;
  • 优点二:可以实现客户与委托类间的解耦,在不修改委托类代码的情况下能够做一些额外的处理。

静态代理的局限在于运行前必须编写好代理类

动态代理:

代理类在程序运行时创建的代理方式被成为动态代理。(是不是想到了反射)

也就是说,这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。

例子:

假设我们要实现这样一个需求:

在执行委托类中的方法之前输出“before”,在执行完毕后输出“after”。

我们还是以上面例子中的Vendor类作为委托类,BusinessAgent类作为代理类来进行介绍。

首先我们来使用静态代理来实现这一需求,相关代码如下:

  1. package First;
  2. /*
  3. * 代理类:微商
  4. */
  5. public class BusinessAgent implements Sell {
  6.  
  7. //引用委托类
  8. private Vendor vendor;
  9.  
  10. public BusinessAgent(Vendor vendor) {
  11. this.vendor = vendor;
  12. }
  13.  
  14. @Override
  15. public void sell() {
  16. System.out.println("before");
  17. vendor.sell();
  18. System.out.println("after");
  19. }
  20.  
  21. @Override
  22. public void ad() {
  23. System.out.println("before");
  24. vendor.ad();
  25. System.out.println("after");
  26. }
  27.  
  28. }

从以上代码中我们可以了解到,通过静态代理实现我们的需求需要我们在每个方法中都添加相应的逻辑,

这里只存在两个方法所以工作量还不算大,假如Sell接口中包含上百个方法呢?这时候使用静态代理就会编写许多冗余代码。

通过使用动态代理,我们可以做一个“统一指示”,从而对所有代理类的方法进行统一处理,而不用逐一修改每个方法。

下面我们来具体介绍下如何使用动态代理方式实现我们的需求:

一、使用动态代理

(1)委托类的定义

  1. package First;
  2. /*
  3. * 委托类:厂家
  4. */
  5. public class Vendor implements Sell{
  6.  
  7. @Override
  8. public void sell() {
  9. System.out.println("sell method");
  10. }
  11.  
  12. @Override
  13. public void ad() {
  14. System.out.println("ad method");
  15. }
  16.  
  17. }

(2)中介类(调用处理器)

中介类必须实现InvocationHandler接口,作为调用处理器”拦截“对代理类方法的调用。

InvocationHandler接口(java.lang.reflect包下)

这个接口的定义如下:

  1. public interface InvocationHandler {
  2. Object invoke(Object proxy, Method method, Object[] args);
  3. }

  

  从InvocationHandler这个名称我们就可以知道,实现了这个接口的中介类用做“调用处理器”。

  当我们调用代理类对象的方法时,这个“调用”会转送到invoke方法中,代理类对象作为proxy参数传入,参数method标识了我们具体调用的是代理类的哪个方法,args为这个方法的参数。这样一来,我们对代理类中的所有方法的调用都会变为对invoke的调用,

  这样我们可以在invoke方法中添加统一的处理逻辑(也可以根据method参数对不同的代理类方法做不同的处理)。因此我们只需在中介类的invoke方法实现中输出“before”,然后调用委托类的invoke方法,再输出“after”。下面我们来一步一步具体实现它。

中介类的定义如下:

  1. package First;
  2. /*
  3. * 中介类:实现类
  4. */
  5. import java.lang.reflect.Method;
  6.  
  7. public class DynamicProxy implements InvocationHandler{
  8.  
  9. private Object obj;//obj为委托类对象
  10.  
  11. public DynamicProxy(Object obj){
  12. this.obj = obj;
  13. }
  14.  
  15. @Override
  16. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  17. System.out.println("before");
  18. Object result = method.invoke(obj, args);
  19.  
  20. System.out.println("before");
  21. return result;
  22. }
  23.  
  24. }

(3)动态生成代理类

  1. package First;
  2. /*
  3. * 动态生成代理类
  4. */
  5. import java.lang.reflect.Proxy;
  6.  
  7. public class Main {
  8.  
  9. public static void main(String[] args) {
  10.  
  11. DynamicProxy inter = new DynamicProxy(new Vendor());
  12. /*
  13. * 1. 获取代理类实例sell (它的实现类是Vendor)
  14. * 2. newProxyInstance方法来获取一个代理类实例
  15. * 3. newProxyInstance(代理类的ClassLoader , 接口类Sell , 动态代理的实现类DynamicProxy)
  16. */
  17. Sell sell = (Sell)(Proxy.newProxyInstance(Sell.class.getClassLoader(), new Class[] {Sell.class}, inter));
  18. sell.sell();
  19. sell.ad();
  20. }
  21.  
  22. }

我们运行一下,看看我们的动态代理是否能正常工作。我这里运行后的输出为:

  1. before
  2. sell method
  3. after
  4. before
  5. ad method
  6. after

AOP的通知也是这样实现的吧

在以上代码中,我们调用Proxy类的newProxyInstance方法来获取一个代理类实例。这个代理类实现了我们指定的接口并且会把方法调用分发到指定的调用处理器。

这个方法的声明如下:

  1. public static Object newProxyInstance(ClassLoader loader,
  2. Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

  

方法的三个参数含义分别如下:

  • loader:定义了代理类的ClassLoder;
  • interfaces:代理类实现的接口列表
  • h:调用处理器,也就是我们上面定义的实现了InvocationHandler接口的类实例 ( 即DynamicProxy类 )

  

参考:

http://www.jianshu.com/p/cbd58642fc08

目前还没有理解动态代理,以上只是做个笔记加深我自己的印象

Java代理:静态代理、动态代理的更多相关文章

  1. Java之代理(jdk静态代理,jdk动态代理,cglib动态代理,aop,aspectj)

    一.概念 代理是什么呢?举个例子,一个公司是卖摄像头的,但公司不直接跟用户打交道,而是通过代理商跟用户打交道.如果:公司接口中有一个卖产品的方法,那么公司需要实现这个方法,而代理商也必须实现这个方法. ...

  2. Java代理(静态代理、JDK动态代理、CGLIB动态代理)

    Java中代理有静态代理和动态代理.静态代理的代理关系在编译时就确定了,而动态代理的代理关系是在运行期确定的.静态代理实现简单,适合于代理类较少且确定的情况,而动态代理则给我们提供了更大的灵活性. J ...

  3. 静态代理和利用反射形成的动态代理(JDK动态代理)

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

  4. Java中的JDK动态代理

    所谓代理,其实就是相当于一个中间人,当客户端需要服务端的服务时,不是客户直接去找服务,而是客户先去找代理,告诉代理需要什么服务,然后代理再去服务端找服务,最后将结果返回给客户. 在日常生活中,就拿买火 ...

  5. Java核心技术点之动态代理

    本篇博文会从代理的概念出发,介绍Java中动态代理技术的使用,并进一步探索它的实现原理.由于个人水平有限,叙述中难免出现不清晰或是不准确的地方,希望大家可以指正,谢谢大家:) 一.概述 1. 什么是代 ...

  6. 代理模式 & Java原生动态代理技术 & CGLib动态代理技术

    第一部分.代理模式  代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常 ...

  7. Java Proxy和CGLIB动态代理原理

    动态代理在Java中有着广泛的应用,比如Spring AOP,Hibernate数据查询.测试框架的后端mock.RPC,Java注解对象获取等.静态代理的代理关系在编译时就确定了,而动态代理的代理关 ...

  8. 静态代理与JDK动态代理

    demo地址: https://github.com/ZbLeaning/leaning 代理: 为其他对象提供一种代理以控制对这个对象的访问.分为静态代理和动态代理.代理模式的目的就是为真实业务对象 ...

  9. (转)轻松学,Java 中的代理模式及动态代理

    背景:讲到反射机制,肯定会想到动态代理. 轻松学,Java 中的代理模式及动态代理 代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强.值得注意的是,代理类和被代理类应该 ...

  10. Java设计模式-代理模式之动态代理(附源代码分析)

    Java设计模式-代理模式之动态代理(附源代码分析) 动态代理概念及类图 上一篇中介绍了静态代理,动态代理跟静态代理一个最大的差别就是:动态代理是在执行时刻动态的创建出代理类及其对象. 上篇中的静态代 ...

随机推荐

  1. RPG游戏中如何判断敌人是否在玩家的攻击范围之内

    // 方式1:通过主角和场景中的所有敌人比较 private void AtkCondition1(float _range,float _angle) { // 搜索所有敌人列表(在动态创建敌人时生 ...

  2. Python全栈开发-Day12-Mysql数据库和ORM

    本节内容 数据库介绍 mysql 数据库安装使用 mysql管理 mysql 数据类型 常用mysql命令 创建数据库 外键 增删改查表 权限 事务 索引 python 操作mysql ORM sql ...

  3. 在linux中,我为什么不能安装VMware Tools?

    在linux中,我为什么不能安装VMware Tools? 应该是操作不正确导致,以下为linux安装VMware Tools的方法. 1.在安装Linux的虚拟机中,单击“虚拟机”菜单下的“安装Vm ...

  4. 【文献04】无人驾驶高速AWID-AWIS车辆运动控制研究

    参考:阮久宏, 李贻斌, 荣学文, et al. 无人驾驶高速AWID-AWIS车辆运动控制研究[J]. 农业机械学报, 2009, 40(12):37-42. https://drive.wps.c ...

  5. 一、win+git安装

    最近公司版本控制准备弃用svn,采用git.所以在个人系统安装玩了下,留点爪印... 1.下载最新的 git 包(根据电脑系统) 官网地址:https://git-scm.com/download/w ...

  6. 20165303实验一 Java开发环境的熟悉

    实验一简单的java程序编译及运行,文件夹的创建 1.添加文件夹: 命令mkdir+文件夹名称 2.编译,运行Java程序 :javac 主类名.java java 主类名 3.带包(package) ...

  7. 关于新手用java写题目,遇到的字符和字符串问题

    我看到一遍很好的博客: https://blog.csdn.net/qq_37267015/article/details/78738512 1.首先了,java之中,没有像C语言那样的getchar ...

  8. 网站访问出现 ------ Can not write to cache files, please check directory ./cache/ .

    最近在搞微商城时,突然出现了Can not write to cache files, please check directory ./cache/ .这样一个提示, 但最近好像没搞什么大动作,怎么 ...

  9. summary ranges leetcode java

    问题描述: Given a sorted integer array without duplicates, return the summary of its ranges. For example ...

  10. 『MXNet』第十一弹_符号式编程初探

    一.符号分类 符号对我们想要进行的计算进行了描述, 下图展示了符号如何对计算进行描述. 我们定义了符号变量A, 符号变量B, 生成了符号变量C, 其中, A, B为参数节点, C为内部节点! mxne ...