2017-10-4(动态代理)

作者: 721d739b6619 | 来源:发表于2017-10-06 14:08 被阅读64次

    代理分为静态代理和动态代理。

    • 静态代理
      可以看下面代码
    /**
     * 静态代理中代理类和委托类也常常继承同一父类或实现同一接口。
     * 普通业务类
     * 通过接口更加灵活实现代理模式
     */
    public interface Subject {
    
        void visit();
    
    }
    
    /**
     * 委托类
     * 代理类和真实业务类都需要实现业务类的接口
     */
    public class RealSubject implements Subject{
        @Override
        public void visit() {
            //真实业务具体逻辑
            System.out.println("Real Subject");
        }
    }
    
    /**
     * 代理类
     * 代理类和委托类都需要实现业务类的接口
     */
    public class ProxySubject implements Subject {
    
        private Subject iSubject;//委托类
    
        public ProxySubject(Subject subject){
            //关键:关联委托类
            this.iSubject = subject;
        }
    
        @Override
        public void visit() {
            //调用真实业务类的方法
            iSubject.visit();
        }
    }
    
    public class Client {
    
        public static void main(String[] args){
            //构造一个真实主题对象
            RealSubject realSubject = new RealSubject();
    
            //通过真实主题对象构造一个代理对象
            ProxySubject proxySubject = new ProxySubject(realSubject);
    
            //调用代理类的相关方法
            proxySubject.visit();
        }
    }
    

    其实可以看个几个关键点:

    • 代理类和委托类公共实现同一个接口。(其实我觉得这个不是必然的。代理类可以不实现接口。而委托类实现接口是基于面向接口编程这个原则,实现接口使编程更加灵活而已)
    • 这个是核心:就是代理类构建实例需要关联委托类。这样才能调用代理方法,实则是调用委托类的方法实现功能。

    其实静态代理:在实际中不方便直接构建委托对象,而需要代理类实现具体的方法。

    • 动态代理
    public interface DynamicInterface {
        //实现逻辑
        void implement();
    }
    
    /**
      委托类
     * 实现接口
     */
    public class DynamicRealSubject implements DynamicInterface{
    
        @Override
        public void implement() {
            Log.e("DynamicRealSubject","DynamicRealSubject___动态代理模式");
        }
    }
    
    /**
     * 实现InvocationHandler的类是运行时将生成的代理类需要完成的具体任务即invoke方法里面
     * 动态代理
     */
    public class DynamicProxySubject implements InvocationHandler{
    
        private Object sub;//需要被代理的对象
    
        public DynamicProxySubject(Object sub){
            this.sub = sub;
        }
    
        public DynamicProxySubject(){}
    
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Log.e("DynamicProxySubject","动态代理前");
    
            //真正被代理类的方法被调用 method就是被代理的类的方法
            method.invoke(sub,args);
            //proxy这个参数在方法里写会内存溢出
    //        method.invoke(proxy,args);
            Log.e("DynamicProxySubject","动态代理后");
            return null;
        }
    }
    
    
    //实现结果
     public static void main(String[] args) throws Exception {
            DynamicRealSubject realSubject = new DynamicRealSubject();
    
            InvocationHandler handler = new DynamicProxySubject(realSubject);
        
    
            //一次性生成
            DynamicInterface subject = (DynamicInterface)Proxy
                    .newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),handler);
           
    
            //实现动态代理被代理类的方法
            subject.implement();
        }
    
    • java JDK就提供了实现动态代理的方法。涉及到两个类:
      1、InvocationHandler 实现委托类的方法的一个接口
      2、Proxy 代理类

    动态代理与静态代理最大的不同就是代理类非程序员预先定义好,而是在运行时才生成代理类。

    提示:
    我开始时候以为实现InvocationHandler接口的就是代理类,其实是错误的。该类其实提供给Proxy类构造时关联用到的。每当生成代理类实例调用代理方法就会调用实现InvocationHandler接口的类中的invoke方法。

    实现InvocationHandler接口的类
    • 这里构造函数需要关联一下委托类。目的就是在invoke方法里面通过反射调用委托类的方法,其实实现的目的与静态类是一致的。
    • invoke有三个参数 Object这个是代理类。Method 就是通过Proxy生成实例接口里面的方法。而args数组就是method的参数

    看看这个InvocationHandler类到底如何与Proxy有联系的

    DynamicRealSubject realSubject = new DynamicRealSubject();
    InvocationHandler handler = new DynamicProxySubject(realSubject);
    Class cls = realSubject.getClass();
     DynamicInterface subject = 
    (DynamicInterface)Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),handler);          
    

    这样就将InvocationHandler类与Proxy类关联起来。
    看看Proxy.newProxyInstance这个方法是做什么的

    newProxyInstance方法内部

    看到了cl这个变量明显就是一个类对象然后在生成构造函数再构建对象。构建对象时通过h即InvocationHandler这个实例关联一起。整个过程就是这样生成一个代理实例。

    看看getProxyClass0方法生成类对象


    Paste_Image.png

    由于该方法太长截取关键部分:
    这里的generateProxy就是生成类对象,之前的代码是进行缓存。

    看看生成代理对象那代码:

    Paste_Image.png Paste_Image.png

    生成代理对象时,把InvocationHandler实例传进去
    所以它最终生成的代理类是会有InvocationHandler的痕迹的。这里我看了网上的说,生成的代理类是继承Proxy实现委托接口。在代理方法里面InvocationHandler通过反射调用invoke方法。

    相关文章

      网友评论

        本文标题:2017-10-4(动态代理)

        本文链接:https://www.haomeiwen.com/subject/rjjcyxtx.html