原文链接:http://langyu.iteye.com/blog/410071
没事的时候翻看lang.reflect包下的代码,发现有两部分内容:涉及反射和动态代理。
很多地方都可以看到动态代理的影子,只是一直没仔细看下。
在学习之前,先提出几个问题,带着问题来看代码:
1.什么是动态代理?
2.为什么使用动态代理?
3.使用它有哪些好处?
4.哪些地方需要动态代理?
--------------------分隔线-----------------------------
和动态代理有关的有两个类
1.interface InvocationHandler
Object invoke(Object proxy, Method method, Object[] args)
只这一个方法,后面再说
2.class Proxy
真正表示动态代理的类,提供两个静态方法:
Class<?> getProxyClass(ClassLoader loader, Class<?>[] interface)
用来产生代理类,参数要提供interface数组,它会生成这些interface的“虚拟实现”,
用来冒充真实的对象。
Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
产生代理对象,多了InvocationHandler参数(只是InvocationHandler接口的实现类),
它与代理对象关联,当请求分发到代理对象后,会自动执行h.invoke(...)方法,
invoke方法就是我们用来做N多事情的地方 -_-。
--------------------分隔线-----------------------------
看完上面的代码,大致明白动态代理的含义:
A接口有c方法,类B实现A接口,原本应该是执行B类中的c方法,可现在不这样做;
我声明产生B类的代理类B',由它来冒充B类的“兄弟”并“实现”A接口,
对外界来说B'应该也有c方法,可当真正调用它的时候,
它会去执行与它关联InvocationHandler的invoke()方法,
在这个方法里面你可以做很多事情。这样,这个请求就被“代理”到其它地方去了。
下面是根据我的理解画的一个说明图
--------------------分隔线-----------------------------
引用网上的一个例子来说明问题(有部分改动,转载自:http://callan.iteye.com/blog/161806)
真实的接口:
- public interface Hello {
- void sayHello(String to);
- void print(String p);
- }
它的真实实现类:
- public class HelloImpl implements Hello {
- public void sayHello(String to) {
- System.out.println("Say hello to " + to);
- }
- public void print(String s) {
- System.out.println("print : " + s);
- }
- }
在这里生成与代理类相关联的InvocationHandler对象
- public class LogHandler implements InvocationHandler {
- private Object dele;
- public LogHandler(Object obj) {
- this.dele = obj;
- }
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- doBefore();
- //在这里完全可以把下面这句注释掉,而做一些其它的事情
- Object result = method.invoke(dele, args);
- after();
- return result;
- }
- private void doBefore() {
- System.out.println("before....");
- }
- private void after() {
- System.out.println("after....");
- }
- }
最后是测试类:
- public class ProxyTest {
- public static void main(String[] args) {
- HelloImpl impl = new HelloImpl();
- LogHandler handler = new LogHandler(impl);
- //这里把handler与impl新生成的代理类相关联
- Hello hello = (Hello) Proxy.newProxyInstance(impl.getClass().getClassLoader(), impl.getClass().getInterfaces(), handler);
- //这里无论访问哪个方法,都是会把请求转发到handler.invoke
- hello.print("All the test");
- hello.sayHello("Denny");
- }
- }
这里是输出结果:
- before....
- print : All the test
- after....
- before....
- Say hello to Denny
- after....
--------------------分隔线-----------------------------
最后试着来回答之前提出的问题:
1.什么是动态代理?
一种用于转发请求,进行特殊处理的机制,“动态”应该指的是“运行期”。
2.为什么使用动态代理?
可以对请求进行任何处理(如事务,日志等,这都是网上说的,我当然可以做任何处理)
3.使用它有哪些好处?
如上
4.哪些地方需要动态代理?
不允许直接访问某些类;对访问要做特殊处理等,我只能想到这些。
--------------------分隔线-----------------------------
其它一些想法:
1.如果想声明产生B类的代理类,那个B类必须要实现接口,如果没有接口,
代理类就不能伪装成B类的“兄弟”,也就没有存在的意思,
其实也可以伪装成B类的“孩子”,对外他们有共同的接口,可以这样做吧?
2.当请求代理类的方法时,这个请求会被转到执行与代理类关联InvocationHandler
的invoke方法。那InvocationHandler到底是什么?对它的理解可以是这样:
它用来处理方法的调用,实现类也有同样的意义;与代理类对象相关联则表示,
它就是负责处理代理类应该有的动作,把所有的方法请求分发到invoke这个方法上。
--------------------分隔线-----------------------------
学习后总结,既可以全面地观察分析,又能加深印象。
如果我的理解有误,别人的指证会对我产生积极影响。
如果我的理解正确,帮助其它
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
原文链接:http://www.open-open.com/home/space-24-do-blog-id-12.html
JAVA代理模式与动态代理模式
1、代理模式
所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用。
代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。
生活中的例子:过年加班比较忙,没空去买火车票,这时可以打个电话到附近的票务中心,叫他们帮你买张回家的火车票,当然这会附加额外的劳务费。但要清楚票务中心自己并不卖票,只有火车站才真正卖票,票务中心卖给你的票其实是通过火车站实现的。这点很重要!
上面这个例子,你就是“客户”,票务中心就是“代理角色”,火车站是“真实角色”,卖票称为“抽象角色”!
代理模式JAVA代码示例:
//抽象角色:抽象类或接口
- interface Business
- {
- void doAction();
- }
//真实角色:真正实现了业务逻辑接口
//代理角色:自己并未实现业务逻辑接口,而是调用真实角色来实现
- class BusinessImplProxy implements Business
- {
- private BusinessImpl bi;
- public void doAction()
- {
- if (bi==null)
- {
- bi = new BusinessImpl();
- }
- doBefore();
- bi.doAction();
- doAfter();
- }
- public void doBefore()
- {
- System.out.println("前置处理!");
- }
- public void doAfter()
- {
- System.out.println("后置处理!");
- }
- }
- //测试类
- class Test
- {
- public static void main(String[] args)
- {
- //引用变量定义为抽象角色类型
- Business bi = new BusinessImplProxy();
- bi.doAction();
- }
- }
所以,借助于JVM的支持,可以在运行时动态生成代理类(“代理角色”),我们就可以解决上述代理模式中代码膨胀的问题,使用了动态代理后,“代理角色”将不用手动生成,而由JVM在运行时,通过指定类加载器、接口数组、调用处理程序这3个参数来动态生成。
动态代理模式JAVA代码示例:
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Proxy;
- import java.lang.reflect.Method;
- //抽象角色:java动态代理的实现目前只支持接口,不支持抽象类
- interface BusinessFoo
- {
- void foo();
- }
- interface BusinessBar
- {
- String bar(String message);
- }
- //真实角色:真正实现业务逻辑方法
- class BusinessFooImpl implements BusinessFoo
- {
- public void foo()
- {
- System.out.println("BusinessFooImpl.foo()");
- }
- }
- class BusinessBarImpl implements BusinessBar
- {
- public String bar(String message)
- {
- System.out.println("BusinessBarImpl.bar()");
- return message;
- }
- }
- //动态角色:动态生成代理类
- class BusinessImplProxy implements InvocationHandler
- {
- private Object obj;
- BusinessImplProxy() {
- }
- BusinessImplProxy(Object obj) {
- this.obj = obj;
- }
- public Object invoke(Object proxy,Method method,Object[] args) throws Throwable
- {
- Object result = null;
- doBefore();
- result = method.invoke(obj,args);
- doAfter();
- return result;
- }
- public void doBefore(){
- System.out.println("do something before Business Logic");
- }
- public void doAfter(){
- System.out.println("do something after Business Logic");
- }
- public static Object factory(Object obj)
- {
- Class cls = obj.getClass();
- return Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),new BusinessImplProxy(obj));
- }
- }
- //测试类
- public class DynamicProxy
- {
- public static void main(String[] args) throws Throwable
- {
- BusinessFooImpl bfoo = new BusinessFooImpl();
- BusinessFoo bf = (BusinessFoo)BusinessImplProxy.factory(bfoo);
- bf.foo();
- System.out.println();
- BusinessBarImpl bbar = new BusinessBarImpl();
- BusinessBar bb = (BusinessBar)BusinessImplProxy.factory(bbar);
- String message = bb.bar("Hello,World");
- System.out.println(message);
- }
- }
程序流程说明:
new BusinessFooImpl();创建一个“真实角色”,传递给工厂方法BusinessImplProxy.factory(),进而初始化“调用处理器”——即实现InvocationHandler的类。并返回一个动态创建的代理类实例,由于“代理角色”也必然实现了“抽象角色”提供的业务逻辑方法,故可向下转型为BusinessBar,并赋值给指向BusinessBar类型的引用bb。
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法由程序员来指定参数动态返回需要的代理类,而invoke(Object proxy, Method method, Object[] args) 方法则是由JVM在运行时动态调用的。当执行“bb.bar("Hello,World");”方法时,JVM动态指派“调用处理器”,向外层invoke传递参数,并调用method.invoke(obj,args)真正执行!
BusinessImplProxy.Factory静态方法用来动态生成代理类(“代理角色”),在运行时根据不同的业务逻辑接口BusinessFoo和BusinessBar,在运行时分别动态生成了代理角色。“抽象角色”、“代理角色”以及调用处理器(实现InvocationHandler接口的类)这三者都可以改变,所以说JAVA的动态代理十分强大。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------原文链接:http://www.cnblogs.com/linjiqin/archive/2011/02/18/1957600.html
Java动态代理一——动态类Proxy的使用
1.什么是动态代理?
答:动态代理可以提供对另一个对象的访问,同时隐藏实际对象的具体事实。代理一般会实现它所表示的实际对象的接口。代理可以访问实际对象,但是延迟实现实际对象的部分功能,实际对象实现系统的实际功能,代理对象对客户隐藏了实际对象。客户不知道它是与代理打交道还是与实际对象打交道。
2.为什么使用动态代理?
答:因为动态代理可以对请求进行任何处理
3.使用它有哪些好处?
答:因为动态代理可以对请求进行任何处理
4.哪些地方需要动态代理?
答:不允许直接访问某些类;对访问要做特殊处理等
目前Java开发包中包含了对动态代理的支持,但是其实现只支持对接口的的实现。 其实现主要通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。
Proxy类主要用来获取动态代理对象,InvocationHandler接口用来约束调用者实现
以下为模拟案例,通过动态代理实现在方法调用前后向控制台输出两句字符串
目录结构
<br/>
定义一个HelloWorld接口
1 package com.ljq.test; 2 3 /** 4 * 定义一个HelloWorld接口 5 * 6 * @author jiqinlin 7 * 8 */ 9 public interface HelloWorld { 10 public void sayHelloWorld(); 11 }
<br/>
类HelloWorldImpl是HelloWorld接口的实现
1 package com.ljq.test; 2 3 /** 4 * 类HelloWorldImpl是HelloWorld接口的实现 5 * 6 * @author jiqinlin 7 * 8 */ 9 public class HelloWorldImpl implements HelloWorld{ 10 11 public void sayHelloWorld() { 12 System.out.println( " HelloWorld! " ); 13 } 14 15 }
HelloWorldHandler是 InvocationHandler接口实现
1 package com.ljq.test; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 6 /** 7 * 实现在方法调用前后向控制台输出两句字符串 8 * 9 * @author jiqinlin 10 * 11 */ 12 public class HelloWorldHandler implements InvocationHandler{ 13 // 要代理的原始对象 14 private Object obj; 15 16 public HelloWorldHandler(Object obj) { 17 super (); 18 this .obj = obj; 19 } 20 21 /** 22 * 在代理实例上处理方法调用并返回结果 23 * 24 * @param proxy 代理类 25 * @param method 被代理的方法 26 * @param args 该方法的参数数组 27 */ 28 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 29 Object result = null ; 30 // 调用之前 31 doBefore(); 32 // 调用原始对象的方法 33 result = method.invoke(obj, args); 34 // 调用之后 35 doAfter(); 36 return result; 37 } 38 39 private void doBefore(){ 40 System.out.println( " before method invoke " ); 41 } 42 43 private void doAfter(){ 44 System.out.println( " after method invoke " ); 45 } 46 47 }
测试类
package com.ljq.test; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class HelloWorldTest { public static void main(String[] args) { HelloWorld helloWorld = new HelloWorldImpl(); InvocationHandler handler = new HelloWorldHandler(helloWorld); // 创建动态代理对象 HelloWorld proxy = (HelloWorld)Proxy.newProxyInstance( helloWorld.getClass().getClassLoader(), helloWorld.getClass().getInterfaces(), handler); proxy.sayHelloWorld(); } }
运行结果为: