论坛首页 入门技术论坛

代理模式-动态代理

浏览 10932 次
该帖已经被评为新手帖
作者 正文
   发表时间:2010-08-05   最后修改:2010-08-05

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

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

 

    首先要了解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.通过代理调用方法
 

 

 欢迎讨论!! 

   发表时间:2010-08-06   最后修改: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");
    }
}

1 请登录后投票
   发表时间:2010-08-06  
楼主,是干嘛的啊
0 请登录后投票
   发表时间:2010-08-06  
管理员这里既然会有这样的贴子!!!!!!!!!!!!!
0 请登录后投票
   发表时间:2010-08-07  
基础东西回顾下  有新的体会
0 请登录后投票
   发表时间:2010-08-08  
JavaEye上有批比较贱的人,建议楼主把自己的心得什么的记载自己的doc里面,别在javaeye上发。

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

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

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

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

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

+1
0 请登录后投票
   发表时间:2010-08-09  
lz和1F的代码都看了。
我这篇博文可以说是
lz思想的加强版
http://rainsilence.iteye.com/blog/684265

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

to 1f
同意把factory方法独立出去,但是不同意你把它改成非静态。
0 请登录后投票
论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics