Proxy - 代理模式

作者: DjangoW | 来源:发表于2018-08-15 18:07 被阅读31次

    注意:全文是基于Java来描述和实现的!
    代理模式的实现有很多种方法:静态代理,动态代理(又分为反射实现的动态代理,CGLib通过修改字节码文件实现的动态代理)。代理模式的目的是解耦Client和Subject,Proxy作为Client和Subject之间的中间人接受Client的操作请求并和Subject交互。通过这种Proxy的方式可以在原操作的基础上添加额外的功能和操作,比如对数据库的读写操作结束之后对读写结果做缓存处理,比如对指定的操作之前和之后做日志的记录。

    静态代理

    代理模式(静态)的类图如下:

    Proxy Pattern

    Java实现如下:
    Subject接口

    interface Subject{
        void request();
    }
    

    RealSubject类

    class RealSubject implements Subject{
        public void request(){
            System.out.println("RealSubject request invoke!");
        }
    }
    

    Proxy类

    class Proxy implements  Subject{
        private Subject subject;
        public Proxy(Subject subject){
            this.subject = subject;
        }
        private void preRequest(){
            System.out.println("preRequest");
        }
        private void postRequest(){
            System.out.println("postRequest");
        }
        public void request(){
            preRequest();
            subject.request();
            postRequest();
        }
    }
    

    Client类

    class Client{
        public static void main(String [] args){
            Proxy subjectProxy = new Proxy(new RealSubject());
            subjectProxy.request();
        }
    }
    

    Proxy的作用就是充当Client和Subject的中间人,告诉Proxy要找Subject做什么,然后Proxy会负责整个调用流程,包括调用前调用后甚至出现Exception的时候要做的额外的工作。

    举个更容易理解的例子:代购。Client是买家,Proxy代购者,Subject是卖家。Client只需要告诉Proxy想买什么产品,而不用管这个产品在怎么买(是online还是线下)和去哪儿买(是本国还是要出国),整个中间所有的细节都由Proxy来负责,而在Subject那边买东西只是整个购买流程的一部分。

    如上就是一个简单的代理模式的实现,也是静态代理的实现。静态代理模式下,如果要针对其他操作提供代理,就需要针对不同的Subject接口实现不同的Proxy代理类。如果代理很多,会造成高代码重复率。
    举一个实际应用的例子,你想通过代理为数据库读写操作加上缓存机制,在读写操作结束后将结果缓存到内存中,数据库读写操作如果都要如上述实现静态代理就太啰嗦了。解决这个问题的一个方法是使用通过Java的反射机制实现的动态代理来代替静态代理。

    动态代理

    interface Subject{
        void request();
    }
    

    RealSubject类

    class RealSubject implements Subject{
        public void request(){
            System.out.println("RealSubject request invoke!");
        }
    }
    

    动态代理类实现:

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class DynamicProxy implements InvocationHandler {
        
        Object tar;
        
        public Object bind(Object tar) {
            this.tar = tar;
            return Proxy.newProxyInstance(tar.getClass().getClassLoader(), tar.getClass().getInterfaces(), this);
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // operations before call the method
            System.out.println("print before dynamic proxy invoke method of target");
            return method.invoke(tar, args);
                   // operations after call the method
            System.out.println("print before dynamic proxy invoke method of target");
        }
    }
    

    调用代码:

    class Client{
        public static void main(String [] args){
            Subject vender = (Subject) new DynamicProxy().bind(new RealSubject());
            vender.request();
        }
    }
    

    针对不同的接口Subject,不需要再提供不同的Proxy代理类的实现,只需要在通过new DynamicProxy()创建代理的时候传入实现了该接口的instance就好。

    可以看出,Java通过反射机制实现动态代理需要被代理对象实现统一的接口,如果想代理没有实现特定接口的对象怎么办呢?这时可以考虑使用CGLib实现的动态代理模式

    相关文章

      网友评论

        本文标题:Proxy - 代理模式

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