• 代理模式


    1. 动态代理是指客户通过代理类来调用其它对象的方法

    2. 代理模式一般涉及到的角色有

        1). 抽象角色:声明真实对象和代理对象的共同接口

        2). 代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。

             同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。

        3). 真实角色:代理角色所代表的真实对象,是我们最终要引用的对象 

    3. Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:

        1). Interface InvocationHandler:该接口中仅定义了一个方法:

             public object invoke(Object obj,Method method,object[] args)

             在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。这个抽象方法在代理类中动态实现。

        2). Proxy:该类即为动态代理类,其中主要包含以下内容:

             a). protected Proxy(InvocationHandler h)          // 构造函数,用于给内部的h赋值。

             b). static Class getProxyClass (ClassLoader loader,Class[] interfaces)   // 获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。

         3). static Object newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)  

             // 返回代理类的一个实例,返回后的代理类可以当作被代理类使用,代理类是实现了真实类所实现接口的一个类
           
    4. 所谓Dynamic Proxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。你当然可以把

        该class的实例当作这些interface中的任何一个来用。当然,这个DynamicProxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个

        handler,由它接管实际的工作。因此,在使用动态代理类时,我们必须实现InvocationHandler接口。  

    5. 动态代理的步骤:

        1). 创建一个实现接口InvocationHandler的类,它必须实现invoke方法

        2). 创建被代理的类以及接口

        3). 通过Proxy的静态方法: newProxyInstance(ClassLoader loader,Class[] interfaces, InvocationHandler h) 创建一个代理,该代理实现了真实类所实现的接口

        4). 通过代理调用方法 

    6. 代理类的定义格式应该为:public class $Proxy1 extends Proxy implements 传入的接口{ }

        详见:http://www.cnblogs.com/frankliiu-java/articles/1896443.html

     7. 关于为什么动态代理中使用接口,而不是直接生成子类代理的个人理解:因为使用继承,无法既完全执行父类方法,又无法增加特定内容。

     

    举例,代码摘自圣思园:

    package com.shengsiyuan.dynamicproxy;
    
    public interface Subject
    {
        public void request();
    }

     

    package com.shengsiyuan.dynamicproxy;
    
    public class RealSubject implements Subject
    {
        public void request()
        {
            System.out.println("From real subject!");
        }
    
    }

     

    package com.shengsiyuan.dynamicproxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    /**
     * 该代理类的内部属性是Object类型,实际使用的时候通过该类的构造方法传递进来一个对象
     * 此外,该类还实现了invoke方法,该方法中的method.invoke其实就是调用被代理对象的将要
     * 执行的方法,方法参数是sub,表示该方法从属于sub,通过动态代理类,我们可以在执行真实对象的方法前后
     * 加入自己的一些额外方法。
     *
     */
    
    public class DynamicSubject implements InvocationHandler
    {
        private Object sub;
        
        public DynamicSubject(Object obj)
        {
            this.sub = obj;
        }
        
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
        {
            System.out.println("before calling: " + method);
            
            method.invoke(sub, args);
            
            System.out.println(args == null);
            
            System.out.println("after calling: " + method);
            
            return null;
        }
        
    }

     

    package com.shengsiyuan.dynamicproxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    
    public class Client
    {
        public static void main(String[] args)
        {
            RealSubject realSubject = new RealSubject();
    
            InvocationHandler handler = new DynamicSubject(realSubject);
    
            Class<?> classType = handler.getClass();
    
            // 下面的代码一次性生成代理
    
            Subject subject = (Subject) Proxy.newProxyInstance(classType.getClassLoader(), realSubject.getClass().getInterfaces(),handler);
    
            subject.request();
    
            System.out.println(subject.getClass());
    
        }
        
    }

     

     

    代理模式的应用场景:

    如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法:

    1、修改原有的方法来适应。这样违反了“对扩展开放,对修改关闭”的原则。

    2、就是采用一个代理类调用原有的方法,且对产生的结果进行控制。这种方法就是代理模式。

    使用代理模式,可以将功能划分的更加清晰,有助于后期维护!

  • 相关阅读:
    [Linux]
    [Nginx]
    [Nginx]
    [Linux]
    [Linux]
    [Linux]
    [Linux]
    [Linux] -Docker修改空间大小
    [Linux]
    [MySql]
  • 原文地址:https://www.cnblogs.com/Jtianlin/p/4175557.html
Copyright © 2020-2023  润新知