详见: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. Android学习笔记- ButterKnife 8.0注解使用介绍

    前言: App项目开发大部分时候还是以UI页面为主,这时我们需要调用大量的findViewById以及setOnClickListener等代码,控件的少的时候我们还能接受,控件多起来有时候就会有一种 ...

  2. 闭包(Closure)基础分析

    闭包(Closure) 本文聚焦于回答2个问题: 在全局作用域中,如何读取函数内部的局部变量? 在全局作用域中,如何修改函数内部的局部变量? 变量作用域 JavaScript语言的作用域,一句话概括就 ...

  3. VMware的安装和使用

    注:内容系兄弟连Linux教程(百度传课:史上最牛的Linux视频教程)的学习笔记. VMware的安装和使用 1. 虚拟机的安装 这里安装虚拟机VMware10,下载安装程序,双击安装-->为 ...

  4. Dapper入门教程(一)——Dapper介绍

    Dapper是什么? Dpper是一款.Net平台简单(Simple)的对象映射库,并且Dapper拥有着"微型ORM之王"的称号.就速度而言与手写ADO.NET SqlDateR ...

  5. Hibernate批量操作(一)

    在项目的开发过程之中,我们常会遇到数据的批量处理问题.在持久层采用Hibernate框架时,在进行批量操作时,需要考虑Hibernate实现机制带来的一些问题. 我们知道在每个Hibernate Se ...

  6. LFLiveKit架构简介

    LFLiveSession LFLiveSession 是整个sdk的核心,提供对外部的主要接口.主要功能有:管理推流开关.管理音视频录制及渲染.管理录制渲染后的音视频编码.管理编码后的数据上传.管理 ...

  7. MySQL的MySQL 的JDBC的安装与使用

    1.配置好环境,主要是安装mysql和下载连接需要的包(我用的是mysql-connector-java-5.1.3-rc-bin.jar) 2.注册驱动  Class.forName("c ...

  8. 605. Can Place Flowers种花问题【leetcode】

    Suppose you have a long flowerbed in which some of the plots are planted and some are not. However, ...

  9. MySQL中的基本知识

    本文是MySQL中的一些基本知识,包括各种基本操作.数据类型和表的约束等. ps:都是自己总结.手打出来的,虽然不是什么新东西,但也勉强算原创吧.. 一.数据库 1.创建:CREATE DATABAS ...

  10. HTML 笔记 基础1

    html 笔记 20170807 晴 <h1>标题</h1> 标题分为6个 从1到6字体逐渐变小 <p>段落</p> <html> < ...