Proxy代理的初识


一、 有这样的需求,如果在不给一个目标的源代码的情况下,要为这个目标类增加一些系统功能,例如,异常处理,日志等等。程序需要怎么处理呢?这个时候就需要用到代理类了,编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同的方法,并在调用方法时,增加上系统功能的代码即可实现。

二、 下面我们来看看代理怎么创建和实例化的?

有3中方式来实例化:(1)内部类的实现方式(2) 上面的 匿名内部类的实现方式。(3) 将 JVM创建动态类及其的实例对象   合二为一的实现方式。   Proxy为我们提供了静态方法newProxyInstance

三、下面看看代码演示:

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;

public class ProxyDemo {

    
    public static void main(String[] args) throws Exception{
        //
        Class  clsProxy1=Proxy.getProxyClass(Collection.class.getClassLoader(),Collection.class);
        System.out.println(clsProxy1.getName());
        
        System.out.println("--------------begin constructors list------");
        /*
         * 按照下面的格式 打印
         * $Proxy0()
         * $Proxy0(InvocationHandler ,int)
         */
        Constructor[] constructors =clsProxy1.getConstructors();
        for(Constructor constructor:  constructors){
            String name =constructor.getName();
            StringBuilder sBuilder = new StringBuilder(name);
            // StringBuilder 和StringBuffer的区别 单线程的时候不用考虑同步安全,StringBuilder效率高。
            //多线程的时候要考虑线程安全,StringBuffer才更好。
            sBuilder.append('(');
            Class[] claszzParams = constructor.getParameterTypes();
            for(Class claszzParam: claszzParams){
                sBuilder.append(claszzParam.getName()).append(',');
            }
            if(claszzParams !=null && claszzParams.length !=0){
                sBuilder.deleteCharAt(sBuilder.length()-1);
            }
            sBuilder.append(')');
            System.out.println(sBuilder.toString());
        }
        
        
        Method[] methods =clsProxy1.getMethods();
        for(Method method:  methods){
            String name =method.getName();
            StringBuilder sBuilder = new StringBuilder(name);
            // StringBuilder 和StringBuffer的区别 单线程的时候不用考虑同步安全,StringBuilder效率高。
            //多线程的时候要考虑线程安全,StringBuffer才更好。
            sBuilder.append('(');
            Class[] claszzParams = method.getParameterTypes();
            for(Class claszzParam: claszzParams){
                sBuilder.append(claszzParam.getName()).append(',');
            }
            if(claszzParams !=null && claszzParams.length !=0){
                sBuilder.deleteCharAt(sBuilder.length()-1);
            }
            sBuilder.append(')');
            System.out.println(sBuilder.toString());
        }
        
        System.out.println("--------begin 创建实例对象------");
        // Object obj = clsProxy1.newInstance();  只能实例化 无参的构造方法。
        Constructor constructor = clsProxy1.getConstructor(InvocationHandler.class);
        
        //(1)内部类的实现方式
        class MyInvocationHandler1 implements InvocationHandler  // 其实可以用匿名内部类来写
        {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                return null;
            }
        }
        //此处要是InvocationHandler的一个对象,而InvocationHandler是一个接口,所以只能new他的实现类。
        Collection proxy1=(Collection)constructor.newInstance(new MyInvocationHandler1());
        System.out.println(proxy1);// 结果为null ,可能对象是null,也可能proxy.toString返回的是null。但是如果对象为null,会发生空指针异常。
        proxy1.clear();  //返回值为 void
//        proxy1.size(); // 返回值为 int
        
        
        //(2) 上面的 匿名内部类的实现方式。
        Collection proxy2 = (Collection)constructor.newInstance(new InvocationHandler(){
            @Override
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                return null;
            }
        });
        
        // (3) 将 JVM创建动态类及其的实例对象   合二为一的实现方式。   Proxy为我们提供了静态方法newProxyInstance
        Collection  proxy3 = (Collection)Proxy.newProxyInstance(
                Collection.class.getClassLoader(), // 第一个参数 类加载器
                new Class[]{Collection.class},// 第二个参数  接口的数组, 注意是 大括号。
                new InvocationHandler(){     // 第三个参数 handler的实例对象
                    ArrayList  target =new ArrayList();
                    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();
                        //如何把 要在代理中添加的功能,封装成一对象,作为参数,而不是生硬的把功能写在里面。详细参考ProxyDemo1
                        System.out.println(method.getName()+"running  time of"+(endTime-beginTime));
                        return retVal;
                    }
                
                });
                
        // 每调用一次add 都会调用一次InvocationHandler的invoke方法,代理对象,代理对象的方法,代理对象的方法参数这三要素传递给invoke。
        proxy3.add("zxx");
        //代理对象proxy3,代理对象的方法add,代理对象的方法参数"zxx",这3个参数传递给代理对象的invoke。然后执行完InvocationH andler()
        //的返回值 是一个Object,其实就相当于  Object obj = proxy3.add("zxx");
        proxy3.add("bxd");
        proxy3.add("lhm");
        System.out.println(proxy3.size());   
        
    }

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值