详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt205

利用Java反射机制你可以在运行期动态的创建接口的实现。java.lang.reflect.Proxy类就可以实现这一功能。这个类的名字(译者注:Proxy意思为代理)就是为什么把动态接口实现叫做动态代理。动态的代理的用途十分广泛,比如数据库连接和事物管理(transaction management)还有单元测试时用到的动态mock对象以及AOP中的方法拦截功能等等都使用到了动态代理。

创建代理你可以通过使用Proxy.newProxyInstance()方法创建动态代理。newProxyInstance()方法有三个参数:
1、类加载器(ClassLoader)用来加载动态代理类。
2、一个要实现的接口的数组。
3、一个InvocationHandler把所有方法的调用都转到代理上。
如下例:
1InvocationHandler handler = new MyInvocationHandler();
2MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
3                            MyInterface.class.getClassLoader(),
4                            new Class[] { MyInterface.class },
5                            handler);
在执行完这段代码之后,变量proxy包含一个MyInterface接口的的动态实现。所有对proxy的调用都被转向到实现了InvocationHandler接口的handler上。有关InvocationHandler的内容会在下一段介绍。

InvocationHandler接口在前面提到了当你调用Proxy.newProxyInstance()方法时,你必须要传入一个InvocationHandler接口的实现。所有对动态代理对象的方法调用都会被转向到InvocationHandler接口的实现上,下面是InvocationHandler接口的定义:
1public interface InvocationHandler{
2  Object invoke(Object proxy, Method method, Object[] args)
3         throws Throwable;
4}
下面是它的实现类的定义:
1public class MyInvocationHandler implements InvocationHandler{
2
3  public Object invoke(Object proxy, Method method, Object[] args)
4  throws Throwable {
5    //do something "dynamic"
6  }
7}
传入invoke()方法中的proxy参数是实现要代理接口的动态代理对象。通常你是不需要他的。
invoke()方法中的Method对象参数代表了被动态代理的接口中要调用的方法,从这个method对象中你可以获取到这个方法名字,方法的参数,参数类型等等信息。关于这部分内容可以查阅之前有关Method的文章。
Object数组参数包含了被动态代理的方法需要的方法参数。注意:原生数据类型(如int,long等等)方法参数传入等价的包装对象(如Integer, Long等等)。

常见用例动态代理常被应用到以下几种情况中

     * 数据库连接以及事物管理
     * 单元测试中的动态Mock对象
     * 自定义工厂与依赖注入(DI)容器之间的适配器
     * 类似AOP的方法拦截器

数据库连接以及事物管理Spring框架中有一个事物代理可以让你提交/回滚一个事物。它的具体原理在 Advanced Connection and Transaction Demarcation and Propagation一文中有详细描述,所以在这里我就简短的描述一下,方法调用序列如下:
1web controller --> proxy.execute(...);
2  proxy --> connection.setAutoCommit(false);
3  proxy --> realAction.execute();
4    realAction does database work
5  proxy --> connection.commit();

单元测试中的动态Mock对象Butterfly Testing工具通过动态代理来动态实现桩(stub),mock和代理类来进行单元测试。在测试类A的时候如果用到了接口B,你可以传给A一个实现了B接口的mock来代替实际的B接口实现。所有对接口B的方法调用都会被记录,你可以自己来设置B的mock中方法的返回值。
而且Butterfly Testing工具可以让你在B的mock中包装真实的B接口实现,这样所有调用mock的方法都会被记录,然后把调用转向到真实的B接口实现。这样你就可以检查B中方法真实功能的调用情况。例如:你在测试DAO时你可以把真实的数据库连接包装到mock中。这样的话就与真实的情况一样,DAO可以在数据库中读写数据,mock会把对数据库的读写操作指令都传给数据库,你可以通过mock来检查DAO是不是以正确的方式来使用数据库连接,比如你可以检查是否调用了connection.close()方法。这种情况是不能简单的依靠调用DAO方法的返回值来判断的。

自定义工厂与依赖注入(DI)容器之间的适配器依赖注入容器Butterfly Container有一个非常强大的特性可以让你把整个容器注入到这个容器生成的bean中。但是,如果你不想依赖这个容器的接口,这个容器可以适配你自己定义的工厂接口。你仅仅需要这个接口而不是接口的实现,这样这个工厂接口和你的类看起来就像这样:
1public interface IMyFactory {
2  Bean   bean1();
3  Person person();
4  ...
5}

01public class MyAction{
02
03  protected IMyFactory myFactory= null;
04
05  public MyAction(IMyFactory factory){
06    this.myFactory = factory;
07  }
08
09  public void execute(){
10    Bean bean = this.myFactory.bean();
11    Person person = this.myFactory.person();
12  }
13
14}
当MyAction类调用通过容器注入到构造方法中的IMyFactory实例的方法时,这个方法调用实际先调用了IContainer.instance()方法,这个方法可以让你从容器中获取实例。这样这个对象可以把Butterfly Container容器在运行期当成一个工厂使用,比起在创建这个类的时候进行注入,这种方式显然更好。而且这种方法没有依赖到Butterfly Container中的任何接口。

类似AOP的方法拦截器Spring框架可以拦截指定bean的方法调用,你只需提供这个bean继承的接口。Spring使用动态代理来包装bean。所有对bean中方法的调用都会被代理拦截。代理可以判断在调用实际方法之前是否需要调用其他方法或者调用其他对象的方法,还可以在bean的方法调用完毕之后再调用其他的代理方法。

Java 反射之动态代理的更多相关文章

  1. Java反射和动态代理

    Java反射 反射机制 RTTI 编译器在编译时打开和检查*.class文件 反射机制 运行时打开和检查*.class文件 Java反射常见的方法 java反射的应用 setAccessible(bo ...

  2. Java 反射 设计模式 动态代理机制详解 [ 转载 ]

    Java 反射 设计模式 动态代理机制详解 [ 转载 ] @author 亦山 原文链接:http://blog.csdn.net/luanlouis/article/details/24589193 ...

  3. Java反射机制动态代理

    1.什么事反射机制动态代理 在一段代码的前后动态执行其他操作,比如有一个方法是往数据库添加一个记录,我们可以通过动态代理,在操作数据库方法的前和后添加代码执行打开数据库连接和关闭数据库连接. 2.演示 ...

  4. java反射和动态代理实现与原理详细分析

    关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理. 一.代理模式    代理模式是常用的java设计模式, ...

  5. java反射实现动态代理

    参考:http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html http://my.oschina.net/lyp3314/b ...

  6. Java反射与动态代理

    Java反射机制可以动态地获取类的结构,动态地调用对象的方法,是java语言一个动态化的机制.java动态代理可以在不改变被调用对象源码的前提下,在被调用方法前后增加自己的操作,极大地降低了模块之间的 ...

  7. Java反射 - 3(动态代理)

    动态代理是对包装模式的升级,可以动态的传入需要代理的对象实现代理 准备如下 1. 被代理类的接口 2.被代理类 3.处理器:InvocationHandler 4.代理调用:Proxy.newInst ...

  8. java反射与动态代理的理解

    一.什么是反射机制? 反射的官方定义是这样的:在运行状态中,对于任意的一个类,都能够知道这个类的所有属性和方法,对任意一个对象都能够通过反射机制调用一个类的任意方法,这种动态获取类信息及动态调用类对象 ...

  9. java反射以及动态代理的学习

    java反射学习 1)字节码文件的三种获取方式 ①:Object类的getClass()方法:对象.getClass() ②:数据类型的静态的class属性:类名.class ③:通过Class类的静 ...

随机推荐

  1. teamviewer试用期到期解决

    1.命令行输入:%appdata%删除teamviewer文件夹2.命令行输入:regedit删除teamviewer文件夹3.卸载tv4.控制面板->设备管理器->网络适配器->f ...

  2. 用SSH解决大局域网反向端口转发问题

    本文作者Tony Lee,转载自FreeBuf.COM ​​自从家里换了联通光纤后,联通就在我家宽带出口前搭了一个路由器,我家也彻底沦为192.168.1.0/24段的局域网了,带来的问题就是在外网无 ...

  3. ASP.NET Core - Razor 页面简介

    简介 随着ASP.NET Core 2 即将来临,最热门的新事物是Razor页面.在之前的一篇文章中,我们简要介绍了ASP.NET Core Razor 页面. Razor页面是ASP.NET Cor ...

  4. akoj-1055-矩阵乘法

    矩阵乘法 Time Limit:1000MS  Memory Limit:65536K Total Submit:19 Accepted:7 Description 矩阵乘法是线性代数中最基本的运算之 ...

  5. RSA简介(三)——寻找质数

    要生成RSA的密钥,第一步就是要寻找质数,本节专讲如何寻找质数. 我们的质数(又称素数).合数一般是对正整数来讲,质数就是只有1和本身两个的正整数,合数至少有3个约数,而1既不是合数也不是质数. 质数 ...

  6. java8之lambda表达式入门

    1.基本介绍 lambda表达式,即带有参数的表达式,为了更清晰地理解lambda表达式,先上代码: 1.1 两种方式的对比 1.1.1 方式1-匿名内部类 class Student{ privat ...

  7. angular或者js如何确定选中ul中的哪几个li

    刚来新公司接到新的需求做一个知识库页面 红色的是单选    蓝色的是多选     这些都是需要传递到后台的 开始不知道如何解决  下班后在家想到一个很巧妙的办法  不多说上代码 箭头所指就是在li里写 ...

  8. Linux - 简明Shell编程05 - 条件语句(Case)

    脚本地址 https://github.com/anliven/L-Shell/tree/master/Shell-Basics 示例脚本及注释 #!/bin/bash var=$1 # 将脚本的第一 ...

  9. MySQL锁与MVCC

    --MySQL锁与MVCC --------------------2014/06/29 myisam表锁比较简单,这里主要讨论一下innodb的锁相关问题. innodb相比oracle锁机制简单许 ...

  10. Oracle 高水位线和全表扫描

    --Oracle 高水位线和全表扫描--------------------------2013/11/22 高水位线好比水库中储水的水位线,用于描述数据库中段的扩展方式.高水位线对全表扫描方式有着至 ...