黑马程序员技术交流社区

标题: 动态代理和代理的区别以及如何创建动态代理类。 [打印本页]

作者: 何清林    时间: 2014-3-1 11:34
标题: 动态代理和代理的区别以及如何创建动态代理类。
能具体说说动态代理和代理的区别吗?以及如何创建动态代理类?


作者: 靓仔    时间: 2014-3-1 11:50
这是高新技术里边讲的,在张孝祥老师里边特别讲到的,比如你比如一个类Person,具有买电脑的方法,这是你可以用一个Proxy类实例化Person对象,在调用买电脑的方法,在方法之前后者之后,加上要处理的方法这就是代理
class Person{
     buyCom(){}
}
Proxy{
//在之前或者之后加上你要处理的代码
   Person p = new Person();
   p.buyCom();

}
结合这你在看一遍张孝祥老师的视频就明白了
综合示例代码(用到三个.java文件,张老师的源码,自己加了注释,自己敲精简版的代理):
public class ProxyTest {  
  
    /**  
     * @param args  
     */  
    public static void main(String[] args) throws Exception{  
        // TODO Auto-generated method stub  
        //接收两个参数,一个是后边参数的字节码的加载器,一个是所要实现代理的接口的字节码  
        Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);  
        System.out.println(clazzProxy1.getName());//打印代理的名字     $Proxy0  
         
        System.out.println("----------begin constructors list----------");  
        /*想打印出如下格式:  
         * $Proxy0()  
        $Proxy0(InvocationHandler,int)*/  
        Constructor[] constructors = clazzProxy1.getConstructors();//获取代理的构造函数  
        for(Constructor constructor : constructors){  
            String name = constructor.getName();//获取代理的构造函数的name  
            StringBuilder sBuilder = new StringBuilder(name);  
            sBuilder.append('(');  
            Class[] clazzParams = constructor.getParameterTypes();//获取代理的构造函数的参数  
            for(Class clazzParam : clazzParams){  
                sBuilder.append(clazzParam.getName()).append(',');  
            }  
            if(clazzParams!=null && clazzParams.length != 0)//稳妥的判断是否是一个参数,不是就删掉最后的,  
                sBuilder.deleteCharAt(sBuilder.length()-1);  
            sBuilder.append(')');  
            System.out.println(sBuilder.toString());    //$Proxy0(java.lang.reflect.InvocationHandler)        
        }  
  
        System.out.println("----------begin methods list----------");  
        /*$Proxy0()  
        $Proxy0(InvocationHandler,int)*/  
        Method[] methods = clazzProxy1.getMethods();//获取代理身上的方法  
        for(Method method : methods){  
            String name = method.getName();  
            StringBuilder sBuilder = new StringBuilder(name);  
            sBuilder.append('(');  
            Class[] clazzParams = method.getParameterTypes();  
            for(Class clazzParam : clazzParams){  
                sBuilder.append(clazzParam.getName()).append(',');  
            }  
            if(clazzParams!=null && clazzParams.length != 0)  
                sBuilder.deleteCharAt(sBuilder.length()-1);  
            sBuilder.append(')');  
            System.out.println(sBuilder.toString());              
        }  
         
        System.out.println("----------begin create instance object----------");  
        //Object obj = clazzProxy1.newInstance();  
               //方式一:通过接口的子类创建对象   
        Constructor constructor =  
clazzProxy1.getConstructor(InvocationHandler.class);  
        //获取代理身上的构造函数  
        //创建内部类MyInvocationHandler1,目的是传递给代理的构造器  
        class MyInvocationHandler1 implements InvocationHandler{  
  
            public Object invoke(Object proxy, Method method, Object[] args)  
                    throws Throwable {  
                // TODO Auto-generated method stub  
                return null;  
            }  
         
        }  
        //方式二:匿名内部类   
        Collection proxy1 = (Collection)constructor.newInstance(new MyInvocationHandler1());  
         
        System.out.println(proxy1);//没有错误  
        proxy1.clear();//没有错误  
        //proxy1.size();报错,因为,代理调用size方法,其实是调用了MyInvocationHandler1中的invoke,他的返回值是null  
        //System.out.println("111111111111111");//调试用的  
         
        //用了匿名内部类的方法实现  
        Collection proxy2 = (Collection)constructor.newInstance(new InvocationHandler(){  
  
            public Object invoke(Object proxy, Method method, Object[] args)  
                    throws Throwable {  
                return null;  
            }  
              
        });  
  
  
         
         
        /*下边这部分代码非常重要和精辟*/  
        final ArrayList target = new ArrayList();            
        Collection proxy3 = (Collection)getProxy(target,new MyAdvice());  
        proxy3.add("zxx");  
        proxy3.add("lhm");  
        proxy3.add("bxd");  
        System.out.println(proxy3.size());  
        System.out.println(proxy3.getClass().getName());  
    }  
  
    private static Object getProxy(final Object target,final Advice advice) {  
         
        //方式三,newProxyInstance这个方法需要三个参数,可以直接创建target的代理对象  
        Object proxy3 = Proxy.newProxyInstance(  
                target.getClass().getClassLoader(),  
                /*new Class[]{Collection.class},*/  
                  
                //获取target上的接口  
                target.getClass().getInterfaces(),  
                new InvocationHandler(){  
                  
                    public Object invoke(Object proxy, Method method, Object[] args)  
                            throws Throwable {  
  
                        /*long beginTime = System.currentTimeMillis();  
                        Object retVal = method.invoke(target, args);  
                        long endTime = System.currentTimeMillis();  
                        System.out.println(method.getName() + " running time of " + (endTime - beginTime));  
                        return retVal;*/  
                          
                        //把上边的代码封装到一个类中,让后调用该类的方法,就实现了方法的封装  
                        advice.beforeMethod(method);  
                        Object retVal = method.invoke(target, args);  
                        advice.afterMethod(method);  
                        return retVal;                        
                          
                    }  
                }  
                );  
        return proxy3;  
    }  
  
}  
作者: e.c    时间: 2014-3-1 11:55
代理是概念
动态代理是代理的实现
作者: 张稳    时间: 2014-3-1 14:34
静态的代理即写出代理类和目标类,代理类和目标类实现同一个接口,客户端程序可以通过配置文件的修改来决定调用代理类还是目标类,代理类除了有目标类的代码以为,还添加了有其他功能的代码,比如目标代码运行时间的时长

动态代理的需求就产生了,我们写了许多个目标类,同时还要写许多个代理类,为了提高工作效率,JVM可以在运行期间动态的生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。举个例子,通过调用Proxy类中的方法,我们可以实现Collection类,然后再传入ArrayList类,然后再指定你要修改ArrayList中的方法。然后在调用代理类的这个方法的时候,除了要实施目标中的方法的代码,还要实施你添加的代码。

如果不这样做的话,你就要复制粘贴一份ArrayList类的代码,然后将复制后的文件名字设置成ProxyArrayList,然后在你想要修改的方法中添加代码。这样做挺没有效率的
作者: 午夜b'Boy    时间: 2014-3-1 15:58
代理类代理指定接口,代码写死了,不灵活,动态代理类根据配置文件由虚拟机动态生成字节码,实现AOP(面向方面编程),如代码测试工具,测试功能函数的实现效率,proxy为动态代理类,clazz=proxy.getProxyClass(ClassLoader load,Interface[] intf);获取动态代理类字节码.con=clazz.getConstructor(InvocationHandle. class);获取构造方法.obj=con.newInstance(InvocationHandler inv);创建动态代理对象
作者: hauntedlove    时间: 2014-3-1 17:00
张稳 发表于 2014-3-1 14:34
静态的代理即写出代理类和目标类,代理类和目标类实现同一个接口,客户端程序可以通过配置文件的修改来决定 ...

正解!:lol
作者: hauntedlove    时间: 2014-3-1 17:09
http://layznet.iteye.com/blog/1182924 楼主可以看次篇文章,我在学习过程中也有过相似的疑问。
作者: 何清林    时间: 2014-3-1 23:40
张稳 发表于 2014-3-1 14:34
静态的代理即写出代理类和目标类,代理类和目标类实现同一个接口,客户端程序可以通过配置文件的修改来决定 ...

挺好的,我大概明白了,但是我想总结一下,感觉不大会总结,你能总结一下吗?我也总结一下,看看哪个好
作者: 何清林    时间: 2014-3-1 23:41
张稳 发表于 2014-3-1 14:34
静态的代理即写出代理类和目标类,代理类和目标类实现同一个接口,客户端程序可以通过配置文件的修改来决定 ...

能不能分解解释什么是代理?什么是动态代理?




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2