要理解动态代理,需要先理解反射(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. (转)linux各文件夹的作用

    原文地址:<linux各文件夹的作用> linux下的文件结构,看看每个文件夹都是干吗用的/bin 二进制可执行命令 /dev 设备特殊文件 /etc 系统管理和配置文件 /etc/rc. ...

  2. 关于select的默认样式问题

    select { border: solid 1px #000; appearance:none; -moz-appearance:none; -webkit-appearance:none; pad ...

  3. PHP如何安装redis扩展(Windows下)

    PHP如何安装redis扩展(Windows下) 一.总结 一句话总结:下载扩展的dll,放入指定文件夹(php对应的扩展的目录php/ext),在配置文件php.ini中注册dll 尽量不要选择最新 ...

  4. 在Spring Boot中使用 @ConfigurationProperties 注解, @EnableConfigurationProperties

    但 Spring Boot 提供了另一种方式 ,能够根据类型校验和管理application中的bean. 这里会介绍如何使用@ConfigurationProperties.继续使用mail做例子. ...

  5. ubuntu解压和压缩文件

    .tar 解包:tar xvf FileName.tar打包:tar cvf FileName.tar DirName(注:tar是打包,不是压缩!)———————————————.gz解压1:gun ...

  6. 20170822xlVBA ExportCellPhone

    Public Sub GetCellPhone() Dim CellPhone As String Dim Arr As Variant Dim Brr As Variant Dim n As Lon ...

  7. Django admin 管理工具

    admin 组件的使用 Django 提供了基于 web 的管理工具.Django 自动管理工具是 django.contrib 的一部分. INSTALLED_APPS = [ 'django.co ...

  8. CentOS7 下源代码安装php7

    安装PHP7: php-7.1.2.tar.gz:下载:wget http://cn2.php.net/get/php-7.1.2.tar.gz/from/this/mirror 安装php: # t ...

  9. 配置samba 服务器 共享Linux目录

    配置samba 服务器 共享Linux目录 1.安装: yum install -y samba* 2.修改配置文件 vim /etc/samba/smb.conf [web] path = /usr ...

  10. Vue之vue自动化工具快速搭建单页项目目录

    1 生成项目目录 使用vue自动化工具可以快速搭建单页应用项目目录. 该工具为现代化的前端开发工作流提供了开箱即用的构建配置.只需几分钟即可创建并启动一个带热重载.保存时静态检查以及可用于生产环境的构 ...