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

通俗理解:

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

例子:

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

静态代理:

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

代码实例:

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

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

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

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

1、Sell接口的定义如下:

package First;

public interface Sell {

    void sell();

    void ad();

}

2、Vendor类的定义如下:

package First;
/*
* 委托类:厂家
*/
public class Vendor implements Sell{ @Override
public void sell() {
System.out.println("sell method");
} @Override
public void ad() {
System.out.println("ad method");
} }

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

package First;
/*
* 代理类:微商
*/
public class BusinessAgent implements Sell { private Vendor vendor; public BusinessAgent(Vendor vendor) {
this.vendor = vendor;
} @Override
public void sell() {
vendor.sell();
} @Override
public void ad() {
vendor.ad();
} }

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

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

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

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

4、增加功能版BusinessAgent:

package First;
/*
* 代理类:微商
*/
public class BusinessAgent implements Sell { private Vendor vendor; public BusinessAgent(Vendor vendor) {
this.vendor = vendor;
} @Override
public void sell() {
if(isCollegeStudent()){
vendor.sell();
} } @Override
public void ad() {
vendor.ad();
} public boolean isCollegeStudent(){
//为了好理解,这里直接返回True
return true;
} }

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

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

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

动态代理:

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

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

例子:

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

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

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

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

package First;
/*
* 代理类:微商
*/
public class BusinessAgent implements Sell { //引用委托类
private Vendor vendor; public BusinessAgent(Vendor vendor) {
this.vendor = vendor;
} @Override
public void sell() {
System.out.println("before");
vendor.sell();
System.out.println("after");
} @Override
public void ad() {
System.out.println("before");
vendor.ad();
System.out.println("after");
} }

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

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

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

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

一、使用动态代理

(1)委托类的定义

package First;
/*
* 委托类:厂家
*/
public class Vendor implements Sell{ @Override
public void sell() {
System.out.println("sell method");
} @Override
public void ad() {
System.out.println("ad method");
} }

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

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

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

这个接口的定义如下:

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

  

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

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

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

中介类的定义如下:

package First;
/*
* 中介类:实现类
*/
import java.lang.reflect.Method; public class DynamicProxy implements InvocationHandler{ private Object obj;//obj为委托类对象 public DynamicProxy(Object obj){
this.obj = obj;
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before");
Object result = method.invoke(obj, args); System.out.println("before");
return result;
} }

(3)动态生成代理类

package First;
/*
* 动态生成代理类
*/
import java.lang.reflect.Proxy; public class Main { public static void main(String[] args) { DynamicProxy inter = new DynamicProxy(new Vendor());
/*
* 1. 获取代理类实例sell (它的实现类是Vendor)
* 2. newProxyInstance方法来获取一个代理类实例
* 3. newProxyInstance(代理类的ClassLoader , 接口类Sell , 动态代理的实现类DynamicProxy)
*/
Sell sell = (Sell)(Proxy.newProxyInstance(Sell.class.getClassLoader(), new Class[] {Sell.class}, inter));
sell.sell();
sell.ad();
} }

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

before
sell method
after
before
ad method
after

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

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

这个方法的声明如下:

public static Object newProxyInstance(ClassLoader loader,
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. python requests库与json数据处理详解

    1. http://docs.python-requests.org/zh_CN/latest/user/quickstart.html get方法将参数放在url里面,安全性不高,但是效率高:pos ...

  2. Ubuntu16.04安装8821CE 无线网卡无驱动

    已解决 参考链接:https://unix.stackexchange.com/question ... -mint-18-2 内容 Worked solution (Requirements: ke ...

  3. Getting Started with Processing 第四章总结

    为什么要使用变量: 我们使用变量的一个重要原因就是避免变成过程中的重复工作,如果你重复使用某一个数字超过了一次,就可以考虑使用一个变量来代替它,这样你的程序会更加通用并且易于更新. 定义变量 定义变量 ...

  4. 手动脱UPX压缩壳

    示例程序演示 样例程序选择win7自带的notepad.exe,该程序原本是没有加壳的: 拷贝notepad.exe文件一个副本,重命名为notepad - upx.exe,我们对notepad - ...

  5. 【源码分析】Mybatis使用中,同一个事物里,select查询不出之前insert的数据

    一.问题场景模拟问题:第二次查询和第一次查询结果一模一样,没有查询出我新插入的数据 猜测:第二次查询走了Mybatis缓存 疑问:那为什么会走缓存呢? 1.service方法 @Override @T ...

  6. flex自定义preloader预加载进度条

    flex默认的preloader已经很不错了,可是有时候还是需要自定义的.   需要在要出现自定义预加载的程序的<mx:Application>标签里加入preloader="& ...

  7. 使用absolute布局

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. apicloud 环信总结

    点击链接先查看一下apicloud 环信的文档 https://docs.apicloud.com/Client-API/Open-SDK/easeChat 文档中写了很多,但官方给的文档还是有问题, ...

  9. CentOS6.8逻辑卷管理实战

    CentOS6.8逻辑卷管理实战 要求:利用现有的四块磁盘,创建一个有两个PV组成的大小为80G的名为testvg的VG:要求PE大小为16MB, 而后在卷组中创建大小为5G的逻辑卷testlv:挂载 ...

  10. 创建属性Attribute

    XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(xmlPath); var root = xmlDoc.DocumentElement;//取到 ...