署理模式-动态代理

代理模式-动态代理

     最近在学习代理模式,看了风中叶老师的视频后,有进一步的了解。

下面,我也来说说这个代理模式,也不不明白的地方。欢迎指教:

 

    首先要了解java设计模式中,代理模式是怎样一个概念。代理模式就是为其他对象提供一种代理以达到控制对这个对象的访问。

   

    代理模式中,有三种角色:

    抽象角色:声明真实对象和代理对象的共同接口
    代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装
    真实角色:代理角色所代表的真实对象,是我们最终要引用的对象

 

    举个例子:你有一套二手房想出手,但是你不会亲自找买房人,所以你会选择一间中介,于是中介就会代替你卖出二手房。于是,买家找到中介买房,中介手上没房子的,他只是代替卖家把房子卖给买家。

   

    下面的代码,详细说明了代理过程的实现。

 

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;
import java.util.Vector;

/**
 * 抽象角色:声明真实对象和代理对象的共同接口
 * 代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。
   同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装
 * 真实角色:代理角色所代表的真实对象,是我们最终要引用的对象
 *  
 * 代理类一定要实现了InvocationHandler接口  
 */  
@SuppressWarnings("unchecked")
public class ProxyObject implements InvocationHandler {
	
	//对真实角色的引用
    private Object proxy_obj;   
  
    ProxyObject(Object obj){
        this.proxy_obj = obj;   
    }   
  
    public static Object factory(Object obj){
           //返回对象的类型
        Class cls = obj.getClass();     
        /**
         * newProxyInstance(...)方法返回代理类的一个实例,返回后的代理类可以当作被代理类使用
         * 在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些 interface。
         * 这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作
         */
        return Proxy.newProxyInstance(cls.getClassLoader()/*类加载器?具体作用是?*/, cls.getInterfaces(),new ProxyObject(obj));   
    } 
    
    public void pre () {
    	System.out.println("函数调用前需要做的事情");   
    }
    
    public void post () {
    	System.out.println("函数调用后需要做的事情");   
    }
  
/**  
*实现InvocationHandler接口的invoke  
*第一个参数obj是指代理类(一般用不上),method是被代理的方法,args为该方法的参数数组。 这个抽象方法在代理类中动态实现
*/  
    public Object invoke(Object obj, Method method, Object[] args) throws Throwable {   
    	pre();
        if(args != null){   
            System.out.println("方法有  " + args.length + "    个参数");   
            for(int i = 0; i < args.length; i ++){   
                System.out.println(args[i]);   
            }   
        }
        //利用反射机制动态调用原对象的方法   
         Object mo = method.invoke(proxy_obj, args);   
         
         post ();
        return mo;   
    }   
    
    /**
     * 抽象主题角色 抽象主题角色的实例 = (抽象主题角色)factory(new 真实主题角色()); 
     * @param agr
     */
	public static void main(String agr[]){
		
		List<String> list = (List<String>) factory(new Vector<String>(10));

		list.add("mysupa.com");
		list.add("超级经纪人网");
		System.out.println(list);
    }   
}

 

动态代理步骤:(风中叶老师整理)

1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法
2.创建被代理的类以及接口
3.通过Proxy的静态方法
newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 创建一个代理
4.通过代理调用方法
 

 

 欢迎讨论!! 

1 楼 congdepeng 2010-08-06  
楼主的代码混在一起,看起来更加confused 我改写了一下啊



1.定义一个工厂,其实本质上就是利用这个方法Proxy.newProxyInstance() 产生一个Proxy实例,
package depeng.dynamicProxy;
import java.lang.reflect.Proxy;
public class ProxyFactory {
    Object factory(Object obj){
        Class cls = obj.getClass();
        return Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), new InvocationHandlerObject(obj));
    }
}



2.为什么要代理?就是让代理调用我们额外的方法,注意这个词语“调用”,就是invoke -- invocation
以前要代理,我们需要做2件事
a.构造一个代理
b.实现代理应该调用的方法

现在(a)不需要我们做了,Proxy.newProxyInstance()会帮我们做
我们只要做(b),也就是实现一个接口InvocationHandler,让这个新的代理去调用

package depeng.dynamicProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class InvocationHandlerObject implements InvocationHandler {
    Object acturyObj;

    InvocationHandlerObject(Object o) {
        acturyObj = o;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("InvocationHandlerObject.invoke()..............<in>......... ");
        pre();
        if (args != null) {
            System.out.println(" args.length " + args.length + "    ");
            for (int i = 0; i < args.length; i++) {
                System.out.println(args[i]);
            }
        }
        //这里,有几个对象/类的关系要搞清楚
        //acturyObj 是被代理的对象
        //proxy     是动态生成的代理对象
        //InvocationHandlerObject 是被proxy对象调用的,同时它有调用 acturyObj
        // proxy --> InvocationHandlerObject --> acturyObj
        System.out.println("Action method " + method.getName());
        System.out.println("acturyObj" + acturyObj.getClass());
        System.out.println("proxy" + proxy.getClass());

        Object mo = method.invoke(acturyObj, args);
        post();
        System.out.println("InvocationHandlerObject.invoke()..............<out>......... ");
        return mo;
    }

    public void pre() {
        System.out.println("InvocationHandlerObject.pre()");
    }

    public void post() {
        System.out.println("InvocationHandlerObject.post()");
    }

}


3.下面的客户端就很容易写了

package depeng.dynamicProxy;

import java.util.List;
import java.util.Vector;

public class Client {
    public static void main(String[] args) {
        List list=(List) new ProxyFactory().factory(new Vector(10));
        list.add("add method in list 1");
    }
}

2 楼 kevin_wanwei 2010-08-06  
楼主,是干嘛的啊
3 楼 kevin_wanwei 2010-08-06  
管理员这里既然会有这样的贴子!!!!!!!!!!!!!
4 楼 tllyf 2010-08-07  
基础东西回顾下  有新的体会
5 楼 XTU_xiaoxin 2010-08-08  
JavaEye上有批比较贱的人,建议楼主把自己的心得什么的记载自己的doc里面,别在javaeye上发。

JavaEye上有些垃圾装2的喜欢给别人得帖子投新手贴、隐藏贴什么的,建议楼主在javaeye上只看贴,没必要发帖,免得javaeye上这些垃圾在那装比,自己一篇帖写不出,就会装,整天给别人帖子滥投票
6 楼 冇心人 2010-08-08  
XTU_xiaoxin 写道
JavaEye上有批比较贱的人,建议楼主把自己的心得什么的记载自己的doc里面,别在javaeye上发。

JavaEye上有些垃圾装2的喜欢给别人得帖子投新手贴、隐藏贴什么的,建议楼主在javaeye上只看贴,没必要发帖,免得javaeye上这些垃圾在那装比,自己一篇帖写不出,就会装,整天给别人帖子滥投票

楼上的说的很对...我非常赞同.
7 楼 bluemusic 2010-08-09  
非常同意啊,有些非但写不出而且看都不看就投了新手隐藏帖,完全滥用自己的大脑做出比S11还要多2的举动
8 楼 wt8414 2010-08-09  
冇心人 写道
XTU_xiaoxin 写道
JavaEye上有批比较贱的人,建议楼主把自己的心得什么的记载自己的doc里面,别在javaeye上发。

JavaEye上有些垃圾装2的喜欢给别人得帖子投新手贴、隐藏贴什么的,建议楼主在javaeye上只看贴,没必要发帖,免得javaeye上这些垃圾在那装比,自己一篇帖写不出,就会装,整天给别人帖子滥投票

楼上的说的很对...我非常赞同.

+1
9 楼 rainsilence 2010-08-09  
lz和1F的代码都看了。
我这篇博文可以说是
lz思想的加强版
http://rainsilence.iteye.com/blog/684265

to lz
将pre,post独立出去会更好

to 1f
同意把factory方法独立出去,但是不同意你把它改成非静态。
10 楼 czxiyj 2010-08-09  
应该给予尊重吧,我觉得楼主总结的经验也不错啊?
内容可能不深,但毕竟在分享!
11 楼 XTU_xiaoxin 2010-08-09  
只要他花了时间、花了心思写的帖子,不管内容怎样,都不应该给他投什么新手帖、隐藏贴什么的。
也许你觉得是很简单的东西,但对其他人来说也许有帮助呢,你能保证je上所有人都是高手?
   看到这帖子的投票我很生气,我一看楼主的帖子,至少是认真写的,也经过了他自己的精心排版,何必打击别人的热情呢?
12 楼 jammyjaccy 2010-08-09  
XTU_xiaoxin 写道
只要他花了时间、花了心思写的帖子,不管内容怎样,都不应该给他投什么新手帖、隐藏贴什么的。
也许你觉得是很简单的东西,但对其他人来说也许有帮助呢,你能保证je上所有人都是高手?
   看到这帖子的投票我很生气,我一看楼主的帖子,至少是认真写的,也经过了他自己的精心排版,何必打击别人的热情呢?

同意楼上的,有些人真2,比上不足,比下有余的时候就装装,真牛逼,你自己发东西,出书,牛逼起来也行啊!这个凭什么不让别人发东西了。
13 楼 goldendays 2010-08-26  
jammyjaccy 写道
XTU_xiaoxin 写道
只要他花了时间、花了心思写的帖子,不管内容怎样,都不应该给他投什么新手帖、隐藏贴什么的。
也许你觉得是很简单的东西,但对其他人来说也许有帮助呢,你能保证je上所有人都是高手?
   看到这帖子的投票我很生气,我一看楼主的帖子,至少是认真写的,也经过了他自己的精心排版,何必打击别人的热情呢?

同意楼上的,有些人真2,比上不足,比下有余的时候就装装,真牛逼,你自己发东西,出书,牛逼起来也行啊!这个凭什么不让别人发东西了。

14 楼 wa20463165 2010-08-26  
反正我是对设计模式不清楚,看的挺带劲!谢谢lz了
15 楼 pcchips 2010-08-27  
借机炒作的
16 楼 malixxx 2010-09-08  
管的真 妈 逼 多,以为自己是谁了,操
17 楼 pengzhoushuo 2010-09-08  
前段时间有一些贴,新手跟良好几乎是一样多的,最后还是新手战胜了良好。建议javaEye要改革了,再不然,大多数人真的是只看博客专栏,不看贴了。
18 楼 yanyan_zhl 2010-10-14  
咳,不要说的那么悲剧啊。新手良好又有什么呢?
新手写的谁然不是多深,但更容易上那些新手上手...
19 楼 joknm 2010-10-14  
wt8414 写道
冇心人 写道
XTU_xiaoxin 写道
JavaEye上有批比较贱的人,建议楼主把自己的心得什么的记载自己的doc里面,别在javaeye上发。

JavaEye上有些垃圾装2的喜欢给别人得帖子投新手贴、隐藏贴什么的,建议楼主在javaeye上只看贴,没必要发帖,免得javaeye上这些垃圾在那装比,自己一篇帖写不出,就会装,整天给别人帖子滥投票

楼上的说的很对...我非常赞同.

+1


+1