精华内容
下载资源
问答
  • 代理模式

    2019-04-15 20:04:30
    1.3代理模式UML结构图 2.代理模式的Java实现 2.1用例UML结构图 2.2用例代码 3.JDK对代理模式的支持 3.1JDK动态代理用例实现 3.1.1动态代理UML结构图 3.1.2动态代理用例代码 3.2JDK动态代理原理解析 3.3JDK...

    目录

     

    0.背景介绍

    1.代理模式介绍

    1.1代理模式定义

    1.2代理模式分类

    1.3代理模式UML结构图

    2.代理模式的Java实现

    2.1用例UML结构图

    2.2用例代码

    3.JDK对代理模式的支持

    3.1JDK动态代理用例实现

    3.1.1动态代理UML结构图

    3.1.2动态代理用例代码

    3.2JDK动态代理原理解析

    3.3JDK动态代理总结

    4.总结


    0.背景介绍

    NBA巨星,鹈鹕队的当家球星戴维斯通过自己的经纪人里奇-保罗宣布将不会与鹈鹕队续约,顿时引起轩然大波,外界内行对他的行为褒贬不一,为荣誉也好,金钱也罢,球星转会想要去到更大的舞台展现自己无可厚非。对于此类新闻我们不置可否,只是引以为例,其实对于大部分名人来说,不管是演艺界还是体育界,他们都有自己的经纪人,大部分的明星都会通过自己的经纪人来转述或者表达一些本人的想法,经纪人就相当于代理人的作用,代理自己的对象来做一些事情。

    在软件设计中,为了解决一个问题或者控制对一个对象行为的访问,我们经常会为此类对象设计一个替身(代理),用以与客户端发生实际的交互,比如网络代理,我们为了解决上网的权限问题,会使用网络代理来访问Internet上面的一些信息,又比如远程代理,我们需要通过远程代理访问远程主机的对象,这些都是我们今天要介绍的代理模式的一种。

    1.代理模式介绍

    1.1代理模式定义

    代理模式:为另一个对象提供一个替身或者占位符来控制对这个对象的访问(比如上面的例子中,明星的所有公共行为都是通过自己的经纪人来转述的,其他人无法代替)

    1.2代理模式分类

    以下分类引自Java与模式一书

    远程代理:为一个位于不同的地址空间的对象提供一个局域代表对象。这个不同的地址空间可以是本机器长,也可以在另一台机器中。

    虚拟代理:根据需要创建一个资源消耗较大的对象,使得此对象只在需要时才会被真正创建。

    Copy-on-Write代理:虚拟代理的一种,把复制(克隆)拖延到只有在客户端需要时,才真正创建。

    保护代理:控制对一个对象的访问,如果需要,可以给不同的用户提供不同级别的使用权限。

    Cache代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。

    防火墙代理:保护目标,不让愿意用户接近。

    同步化代理:使几个用户能够同时使用一个对象而没有冲突。

    智能引用代理:当一个对象被引用时,提供一些额外的操作,比如将此对象的调用次数记录下来等。

    本文对上述几种代理模式不会一一详细的介绍,只会介绍所有代理的共同点。

    1.3代理模式UML结构图

    Subject:抽象主题接口,定义了真实主题以及代理主题的公共接口。

    ProxySubject:代理主题,实现了抽象主题接口,内部持有一个具体主题的引用,可以操作真实主题对象,与客户端直接交互,解耦了客户端与真实主题的交互。

    RealSubject:真实主题,实现了抽象主题接口。

    2.代理模式的Java实现

    以下是用Java简单的实现代理模式的用例代码(jdk版本为Java10)

    2.1用例UML结构图

    Person相当于抽象Subject接口,Star是真实的RealSubject,Broker是代理类

    2.2用例代码

    抽象接口:Person

    public interface Person {
    
        void request();
    }

    Person实现类Star

    public class Star implements Person {
        @Override
        public void request() {
            System.out.println("大家好我想换一只球队了");
        }
    }

    Person实现类Broker

    public class Broker implements Person {
    
        private Person person;
    
        public Broker(Person person) {
            this.person = person;
        }
    
        @Override
        public void request() {
            System.out.println("大家好,我是经纪人XXX,我的被代理人想说:");
            this.person.request();
        }
    }

    Client客户端类:

    public class Client {
        public static void main(String[] args) {
            Person star=new Star();
    
            Person broker=new Broker(star);
    
            broker.request();
        }
    }

    运行结果如下:

    3.JDK对代理模式的支持

    以上是用Java简单的实现类代理模式,其实在JDK中天然增加了对代理模式的支持,主要相关的类有两个,一个是Proxy,另一个是InvocationHandler,实现动态代理的主要步骤如下:

    1. 开发人员需要实现InvocationHandler接口来定义自己的InvocationHandler实现类。并且持有一个被代理类的引用。
    2. 通过Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)方法,传入真实主题的信息以及自定义实现的InvocationHandler,动态生成一个代理类。
    3. 通过动态生成的代理类来调用真实主题的目标方法。

    3.1JDK动态代理用例实现

    3.1.1动态代理UML结构图

    其中,Proxy,InvocationHandler是JDK支持的动态代理工具,MyInvocationHandler是我们自己实现的InvocationHandler接口的自定义实现。

    3.1.2动态代理用例代码

    Person以及Star的代码见上一节

    MyInvocationHandler代码

    public class MyInnovationHandler implements InvocationHandler {
        private Person person;
    
        MyInnovationHandler(Person person) {
            this.person = person;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("大家好,我是经纪人XXX,我的被代理人想说:");
            return method.invoke(this.person, args);
        }
    }

    Client代码

    public class ProxyTest {
        public static void main(String[] args) {
            //创建一个真实主题
            Person star = new Star();
            //创建自定义InvocationHandler实现类
            InvocationHandler invocationHandler = new MyInnovationHandler(star);
            //通过Proxy创建动态代理类
            Person person = (Person) Proxy.newProxyInstance(Star.class.getClassLoader(), Star.class.getInterfaces(), invocationHandler);
            //调用主题方法
            person.request();
    
        }
    }

    运行结果如下:

    可以看到,通过JDK对代理模式的支持,运行结果与上一节中结果是一致的。

    3.2JDK动态代理原理解析

    通过JDK自带的动态代理来实现代理模式非常简单,本节,我们来剖析以下JDK动态代理的原理,让大家知其然,更知其所以然

    动态代理类的主要生成是在Proxy的newProxyInstance(...)方法生成的,下面从这个方法开始讲解下动态代理的原理。

    方法源码如下(JDK源码版本为Java10

    public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h) {
            //方法入参有3个,分别是真实主题的类加载器,真实主题实现的接口,以及自定义实现的
            //InvocationHandler接口
    
            //判空操作
            Objects.requireNonNull(h);
    
            //获取SecurityManager,系统的安全校验,不知道是干啥的,可以忽略
            final Class<?> caller = System.getSecurityManager() == null
                                        ? null
                                        : Reflection.getCallerClass();
    
            /*
             * Look up or generate the designated proxy class and its constructor.
             */
            //生成Constructor对象,与类的构造方法有关
            Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);
    
            //根据Constructor对象,以及caller和自定义的InvocationHandler 生成一个代理类
            return newProxyInstance(caller, cons, h);
        }

    以上是newProxyInstance方法的源码,在主要代码上面写了注释,里面主要涉及的方法有两个,分别是getProxyConstructor()方法以及newProxyInstance()方法。

    下面是getProxyConstructor方法的源码,改方法主要的作用是生成与主题相关的Constructor对象,下面是源码以及源码注释

    private static Constructor<?> getProxyConstructor(Class<?> caller,
                                                          ClassLoader loader,
                                                          Class<?>... interfaces)
        {
            // 判断真实主题实现的抽象接口数量,1个走下面逻辑,大于1个走else接口
            if (interfaces.length == 1) {
                
                Class<?> intf = interfaces[0];
                //callser不为空,做安全校验
                if (caller != null) {
                    checkProxyAccess(caller, loader, intf);
                }
                //先走缓存,通过ProxyBuilder生成Constructor对象
                return proxyCache.sub(intf).computeIfAbsent(
                    loader,
                    (ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
                );
            } else {
                // interfaces cloned
                final Class<?>[] intfsArray = interfaces.clone();
                if (caller != null) {
                    checkProxyAccess(caller, loader, intfsArray);
                }
                final List<Class<?>> intfs = Arrays.asList(intfsArray);
                return proxyCache.sub(intfs).computeIfAbsent(
                    loader,
                    (ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
                );
            }
        }

    下面看下ProxyBuilder类的build方法源码

      Constructor<?> build() {
                //获取代理类
                Class<?> proxyClass = defineProxyClass(module, interfaces);
                final Constructor<?> cons;
                try {
                    //创建代理类的带参构造函数,传入参数是constructorParams
                    cons = proxyClass.getConstructor(constructorParams);
                } catch (NoSuchMethodException e) {
                    throw new InternalError(e.toString(), e);
                }
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
                return cons;
            }

    以上代码片段主要做了以下几件事情

    通过defineProxyClass(Module m, List<Class<?>> interfaces)方法动态生成一个代理类,入参主要有两个,一个是Module,一个是需要实现的接口,Module的主要作用是给代理类的包名的时候使用,interfaces是生成的代理类需要实现的接口。看下这个方法的源码

    private static Class<?> defineProxyClass(Module m, List<Class<?>> interfaces) {
                String proxyPkg = null;     // package to define proxy class in
                int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
    
                /*
                 * Record the package of a non-public proxy interface so that the
                 * proxy class will be defined in the same package.  Verify that
                 * all non-public proxy interfaces are in the same package.
                 */
                  //验证需要实现的所有接口的属性是否是public,如果有一个不是public,则生成的代理类
                    //所在的包名跟此非public的接口的包名一致
                for (Class<?> intf : interfaces) {
                    int flags = intf.getModifiers();
                    if (!Modifier.isPublic(flags)) {
                        accessFlags = Modifier.FINAL;  // non-public, final
                        //给pkg赋值,为非public的接口的包名
                        String pkg = intf.getPackageName();
                        if (proxyPkg == null) {
                            proxyPkg = pkg;
                        } else if (!pkg.equals(proxyPkg)) {
                            throw new IllegalArgumentException(
                                    "non-public interfaces from different packages");
                        }
                    }
                }
    
                if (proxyPkg == null) {
                    // 所有的接口都是public,则包名取默认值为:com.sun.proxy
                    proxyPkg = m.isNamed() ? PROXY_PACKAGE_PREFIX + "." + m.getName()
                                           : PROXY_PACKAGE_PREFIX;
                } else if (proxyPkg.isEmpty() && m.isNamed()) {
                    throw new IllegalArgumentException(
                            "Unnamed package cannot be added to " + m);
                }
    
                if (m.isNamed()) {
                    if (!m.getDescriptor().packages().contains(proxyPkg)) {
                        throw new InternalError(proxyPkg + " not exist in " + m.getName());
                    }
                }
    
                //为生成的代理类取名字的后缀数字,从0开始,
                long num = nextUniqueNumber.getAndIncrement();
                //代理类的名字为包名.$Proxy+后缀数字  比如 com.sun.proxy.$Proxy0
                String proxyName = proxyPkg.isEmpty()
                                        ? proxyClassNamePrefix + num
                                        : proxyPkg + "." + proxyClassNamePrefix + num;
    
                ClassLoader loader = getLoader(m);
                trace(proxyName, m, loader, interfaces);
    
                /*
                 * Generate the specified proxy class.
                 */
                //生成代理类的字节码文件
                byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                        proxyName, interfaces.toArray(EMPTY_CLASS_ARRAY), accessFlags);
                try {
                    Class<?> pc = UNSAFE.defineClass(proxyName, proxyClassFile,
                                                     0, proxyClassFile.length,
                                                     loader, null);
                    //放入cache中
                    reverseProxyCache.sub(pc).putIfAbsent(loader, Boolean.TRUE);
                    return pc;
                } catch (ClassFormatError e) {
                    /*
                     * A ClassFormatError here means that (barring bugs in the
                     * proxy class generation code) there was some other
                     * invalid aspect of the arguments supplied to the proxy
                     * class creation (such as virtual machine limitations
                     * exceeded).
                     */
                    throw new IllegalArgumentException(e.toString());
                }
            }
    

    以上代码主要生成了动态代理类,主要有代理类的包名,类名,以及字节码文件,字节码文件,生成字节码的过程在此不详细 介绍了。

    接下来就是调用代理类的construct方法生成构造器对象,传入参数是constructorParams(此参数是个常量   { InvocationHandler.class }

    最后通过调用newProxyInstance方法,返回一个动态代理类的具体实例

    下面看下生成的代理类的源码(反编译之后的代码)

    import base.pattern.proxy.Person;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;
    
    public final class $Proxy0 extends Proxy implements Person {
        private static Method m1;
        private static Method m2;
        private static Method m3;
        private static Method m0;
    
        public $Proxy0(InvocationHandler var1) throws  {
            super(var1);
        }
    
        public final boolean equals(Object var1) throws  {
            try {
                return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
            } catch (RuntimeException | Error var3) {
                throw var3;
            } catch (Throwable var4) {
                throw new UndeclaredThrowableException(var4);
            }
        }
    
        public final String toString() throws  {
            try {
                return (String)super.h.invoke(this, m2, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        public final void request() throws  {
            try {
                //调用我们之前传入的MyInnovationHandlerde的invoke方法,方法名是m3,m3在下面
                super.h.invoke(this, m3, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        public final int hashCode() throws  {
            try {
                return (Integer)super.h.invoke(this, m0, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        static {
            try {
                m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
                m2 = Class.forName("java.lang.Object").getMethod("toString");
                m3 = Class.forName("base.pattern.proxy.Person").getMethod("request");
                m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            } catch (NoSuchMethodException var2) {
                throw new NoSuchMethodError(var2.getMessage());
            } catch (ClassNotFoundException var3) {
                throw new NoClassDefFoundError(var3.getMessage());
            }
        }
    }

    上面是生成的动态代理类的反编译代码,我们需要注意几点

    1. 此动态代理类继承了Proxy类,实现了Person接口,因此也实现了request()方法。
    2. 在request方法中,我们调用了MyInnovationHandler的invoke()方法(在生成代理类的时候传入的),Method是m3。
    3. m3是接口Person的request方法的反射。
    4. 在MyInnovationHandler方法里面我们调用的是Star类的request()方法(看上面MyInnovationHandler的代码即可发现)

    UML结构图如下:

    3.3JDK动态代理总结

    3.1以及3.2节是对JDK动态代理的解析,由于源码比较多,可能解析的没有那么透彻,下面来动态代理的优缺点

    优点:实现简单,不需要自己定义代理类,可以动态的生成代理类

    缺点:从用例可以看出,JDK动态代理仅仅针对的是接口,为什么?看下最后生成的动态代理类的源码,动态代理类继承了Proxy类,由于Java本身只支持单继承,所以只适用于接口,那么如果针对的不是接口,应该怎么做呢,此时应该使用Cglib来实现(本文暂不讲解Cglib了,将会另外文章讲解)

    4.总结

    本文主要讲解了代理模式(静态代理)以及JDK支持的动态代理模式的原理以及用例实现,讲解动态代理的时候源码较多,逻辑优点混乱,也可能自身理解的也没有特别透彻,会继续加深学习。

     

    展开全文
  • 16.2 软件体系结构代理模式 16.2.1 服务注册模式 16.2.2 代理者转发模式 16.2.3 代理者句柄模式 16.2.4 服务发现模式 16.3 面向服务的体系结构的技术支持 16.3.1 Web服务协议 16.3.2 Web服务 16.3.3 注册...
  • 正文此Base结构是以代理模式进行抽取的,先上类UML图了解其结构 呃。。。本人由于第一用这个androidstudio的SimpleUML插件进行生成这个类图,所以Interface不知道怎么做标识,我们姑且以颜色来分辨其是否为接口和...

    前言

    此Base是在编写项目中,进行反复重构所得的产物,如有错误或者不妥之处,请多多指教,以免误人。谢谢。
    

    正文

    此Base结构是以代理模式进行抽取的,先上类UML图了解其结构
    

    这里写图片描述

    呃。。。本人由于第一用这个androidstudio的SimpleUML插件进行生成这个类图,所以Interface不知道怎么做标识,我们姑且以颜色来分辨其是否为接口和抽象类和实体类了。
    绿色:接口
    淡黄:抽象
    蓝色:实体类

    首先先来解说下这个图的结构吧,有三个接口分别为IBaseFragmentIBaseAFIBaseActivityBaseFragment实现了IBaseFragment和IBaseAF接口,SearchFragment继承了BaseFragment(后面的所有Fragment类都继承其BaseFragment)。IBaseAFImpl实现了IBaseAF。BaseActivity实现了IBaseActivity,IBaseAF。MainActivity继承了BaseActivity。在BaseFragment和BaseActivity中创建了IBaseAFImpl对象。

    介绍下IBaseAF(代理与被代理抽取的接口)接口为Activity和Fragment的拥有相同方法的接口,其作用到时候要添加两个组件的通用功能只需在这个接口进行扩展就可以了。如自定义Toast,SharedPrenfrece的读写抽取,创建的文件的文件名常量,以及其他常量等等。

    IBaseFragment为Fragment通用方法的接口,IBaseActivity为为Activity通用方法的接口。这两个接口分别为其项目所有的Activity和Fragment拥有相同功能所抽取的接口。这里就来疑问了,那么为什么不把这个接口直接合并到IBaseAF里面呢?因为如果到时候要改变其所有Fragment或则Activity只需要改变其相应的接口就可以了。这样就不会互相影响了。

    IBaseAFImpl这个类为IBaseAF的实现类了,即为被代理类,也就是实干的类。此类实现了Activity和Fragment通用功能,如自定义Toast和SharedPrenfrece的读与写的抽取,等等。

    BaseFragment和BaseActivity是个抽象类(这个两个类是代理类,并不是说代理类就是为抽象类,只是由于某些功能的需要因此弄成了抽象类),其内部进行了对IBaseAFImpl的实例化。由于这个两个类都实现了IBaseAF接口,因此在其对应的实现的方法里面使用IBaseAFImpl对象调用其相应的方法。

    这样代理模式就写好了,后面的Activity和Fragment只管继承BaseActivity和BaseFragment就可以了。

    对的,就这么完了。似乎会有疑问,这个好像没有什么优势呀,那么我就简单说说优势在哪。举例说明:首先原来在Activity和fragment的里面分别写自定义Toast。这样两个方法逻辑一样,而且不同的类里面,那么就造成的代码有点多余。所以就往上抽。这样具有相同功能的就在被代理类里面,代理类只需要实现接口进行调用就可以了,减少了代码量。还有就是,如果需要在不是Activity和Fragment类里面进行弹出自定义Toast。那么只需要给个上下文然后进行IBaseAF = new IBaseAFImpl(context),然后调用弹出的方法就可以了。也不用去多余的写自定义Toast的业务逻辑了。嗯,其实还有很多好处的。我就不一一例举了。

    因为我很懒,这里木有贴相应的代码,也许代理模式不熟悉的同学看着很懵,不要担心,源码链接在此

    展开全文
  •  代理模式属于GOF23设计模式中结构型中的设计模式,通过代理对象来屏蔽(部分或者屏蔽)对真实对象的直接访问,下UML图:  在代理模式中组件包括:抽象角色接口、代理角色、真实角色。  抽象角色:...

    一、代理模式是什么?

       代理模式属于GOF23设计模式中结构型中的设计模式,通过代理对象来屏蔽(部分或者屏蔽)对真实对象的直接访问,下图为UML图:

     

       在代理模式中组件包括:抽象角色接口、代理角色类、真实角色类。

      抽象角色:声明真实对象和代理对象的共同接口。
      代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
      真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。

      实际上代理又分为动态代理和静态代理,在实际开发中使用比较多的是动态代理。在主题三种将分别对动态代理和静态代理给出具体的示例。

      所谓的静态代理就是由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。而动态代理就是在程序运行时运用反射机制动态创建而成。

     

    二、为什么用代理模式

         1、远程代理,为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实。

         2、虚拟代理,根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真实对象。例如,网页中在图片出来以前现出来文字。

         3、安全代理,用来控制真实对象访问时的权限。

         4智能代理,是指当调用真实的对象时,代理处理另外一些事。

    注:代理模式是AOP编程的核心实现之一。

    三、怎么用代理模式

    3.1:静态代理示例

    源码已经上传GitHub:https://github.com/wanyouxian/DesignPatterns,工程名为:StaticProxy

    定义抽象角色接口:

     1 package com.rocky.staticproxy;
     2 
     3 public interface IRenting
     4 {
     5     /*
     6      * 看房子
     7      */
     8     public void watchingHouse();
     9     
    10     /**
    11      * 签合同
    12      */
    13     public void signContract();
    14     
    15     /**
    16      * 取钥匙
    17      */
    18     public void takeKey();
    19 }
    View Code

    定义代理对象类,实现抽象角色接口,该类持有真实对象引用

     1 package com.rocky.staticproxy;
     2 
     3 public class HouseProxy implements IRenting
     4 {
     5 
     6     private IRenting landLord = null;
     7 
     8     public HouseProxy(IRenting landLord)
     9     {
    10         this.landLord = landLord;
    11     }
    12 
    13     @Override
    14     public void watchingHouse()
    15     {
    16         System.out.println("HouseProxy.watchingHouse");
    17     }
    18 
    19     @Override
    20     public void signContract()
    21     {
    22         landLord.signContract();
    23     }
    24 
    25     @Override
    26     public void takeKey()
    27     {
    28         System.out.println("HouseProxy.takeKey");
    29     }
    30 }
    View Code

    定义真实对象类,实现抽象接口

     1 package com.rocky.staticproxy;
     2 
     3 public class LandLord implements IRenting
     4 {
     5 
     6     @Override
     7     public void watchingHouse()
     8     {
     9         System.out.println("LandLord.watchingHouse");
    10     }
    11 
    12     @Override
    13     public void signContract()
    14     {
    15         System.out.println("LandLord.signContract");
    16     }
    17 
    18     @Override
    19     public void takeKey()
    20     {
    21         System.out.println("LandLord.takeKey");
    22     }
    23 }
    View Code

    编写测试类

     1 package com.rocky.testdriver;
     2 
     3 import com.rocky.staticproxy.HouseProxy;
     4 import com.rocky.staticproxy.IRenting;
     5 import com.rocky.staticproxy.LandLord;
     6 
     7 public class TestDriver
     8 {
     9 
    10     public static void main(String[] args)
    11     {
    12         IRenting landLord = new LandLord();
    13         IRenting houseProxy = new HouseProxy(landLord);
    14         
    15         houseProxy.watchingHouse();
    16         
    17         houseProxy.signContract();
    18         
    19         houseProxy.takeKey();
    20     }
    21 
    22 }
    View Code

     

    3.2:动态代理示例

       动态代理有多种实现方式,并且在开发中实际使用的比较多,特别是AOP编程的核心实现机制。AOP动态代理主要是通过jdk动态代理和cglib动态代理实现,jdk动态代理是由Java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的。总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。还有一点必须注意:jdk动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,jdk动态代理不能应用。下面示例中通过JDK实现动态代理作为演示demo,源码已经上传GitHub:https://github.com/wanyouxian/DesignPatterns,工程名为:DynamicProxy

    定义抽象角色:

     1 package com.rocky.dynamicproxy;
     2 
     3 public interface IRenting
     4 {
     5     /*
     6      * 看房子
     7      */
     8     public void watchingHouse();
     9 
    10     /**
    11      * 签合同
    12      */
    13     public void signContract();
    14 
    15     /**
    16      * 取钥匙
    17      */
    18     public void takeKey();
    19 }
    View Code

    定义真实对象类:

     1 package com.rocky.dynamicproxy;
     2 
     3 public class LandLord implements IRenting
     4 {
     5 
     6     @Override
     7     public void watchingHouse()
     8     {
     9         System.out.println("房东把房子挂到中介");
    10     }
    11 
    12     @Override
    13     public void signContract()
    14     {
    15         System.out.println("房东自己签租房合同");
    16         
    17     }
    18 
    19     @Override
    20     public void takeKey()
    21     {
    22         System.out.println("中介把房子钥匙给房客");
    23         
    24     }
    25 
    26 }
    View Code

    定义代理对象处理器:

     1 package com.rocky.dynamicproxy;
     2 
     3 public class LandLord implements IRenting
     4 {
     5 
     6     @Override
     7     public void watchingHouse()
     8     {
     9         System.out.println("房东把房子挂到中介");
    10     }
    11 
    12     @Override
    13     public void signContract()
    14     {
    15         System.out.println("房东自己签租房合同");
    16         
    17     }
    18 
    19     @Override
    20     public void takeKey()
    21     {
    22         System.out.println("中介把房子钥匙给房客");
    23         
    24     }
    25 
    26 }
    View Code

    编写测试类:

     1 package com.rocky.testdriver;
     2 
     3 import java.lang.reflect.Proxy;
     4 
     5 import com.rocky.dynamicproxy.IRenting;
     6 import com.rocky.dynamicproxy.LandLord;
     7 import com.rocky.dynamicproxy.RentInvocationHandler;
     8 
     9 public class TestDriver
    10 {
    11 
    12     public static void main(String[] args)
    13     {
    14         IRenting landLord = new LandLord();
    15         RentInvocationHandler handler = new RentInvocationHandler(landLord);
    16 
    17         IRenting proxy = (IRenting) Proxy.newProxyInstance(landLord.getClass().getClassLoader(),
    18                 landLord.getClass().getInterfaces(), handler);
    19 
    20         proxy.watchingHouse();
    21         proxy.signContract();
    22         proxy.takeKey();
    23     }
    24 
    25 }
    View Code

     

    转载于:https://www.cnblogs.com/doitbyyourself/p/7124895.html

    展开全文
  • 目录 1.静态代理 2.动态代理 2.1JDK动态代理 2.2CGlib动态代理 3.静态代理和动态代理的区别: ...UML类结构图: 代码实现: (以父亲给儿子介绍对象为例) Person接口 public inter...

    目录

    1.静态代理

    2.动态代理

    2.1JDK动态代理

    2.2CGlib动态代理

    3.静态代理和动态代理的区别:

    4.代理模式的优缺点


        代理模式:为其他对象提供一种代理以控制这个对象的访问。

        目的:1.保护目标对象;2.增强目标对象

    1.静态代理

    UML类结构图:

    代码实现:

    (以父亲给儿子介绍对象为例)

    Person接口

    public interface Person {
        void findLove();
    }

    Son类

    public class Son implements Person {
        public void findLove() {
            System.out.println("儿子要求:肤白貌美大长腿");
        }
    }

    Father类

    public class Father implements Person {
        private Person person;
    
        public Father(Person person) {
            this.person = person;
        }
    
        public void findLove() {
            System.out.println("父亲物色对象");
            person.findLove();
            System.out.println("双方父母同意,确认关系");
        }
    }

    测试代码:

    public class FatherProxyTest {
        public static void main(String[] args) {
            Father father = new Father(new Son());
            father.findLove();
        }
    }

    输出结果:

    父亲物色对象
    儿子要求:肤白貌美大长腿
    双方父母同意,确认关系

    2.动态代理

    (此处以媒婆给闺女相亲为例)

    2.1JDK动态代理

    UML类结构图:

    代码实现:

    Person接口

    public interface Person {
        void findLove();
    }

    Girl类

    public class Girl implements Person {
        public void findLove() {
            System.out.println("高富帅");
            System.out.println("身高180cm");
            System.out.println("有6块腹肌");
        }
    }
    JDKMeipo类
    public class JDKMeipo implements InvocationHandler {
    
        private Object target;
    
        public Object getInstance(Object obj) throws Exception {
            this.target = obj;
            Class<?> clazz = target.getClass();
            return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            before();
            Object obj = method.invoke(this.target, args);
            after();
            return obj;
        }
    
        private void before() {
            System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求");
            System.out.println("开始物色");
        }
    
        private void after() {
            System.out.println("OK的话,准备办事");
        }
    }

    测试代码:

    public class JDKProxyTest {
    
        public static void main(String[] args) {
            try {
                Object obj = new JDKMeipo().getInstance(new Girl());
                Method method = obj.getClass().getMethod("findLove", null);
                method.invoke(obj);
    
                // JDK动态代理是动态生成一个$Proxy0动态类,
                // 可以通过以下代码将$Proxy0动态类输出到指定路径下,反编译查看
    //            byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class});
    //            FileOutputStream os = new FileOutputStream("E://$Proxy0.class");
    //            os.write(bytes);
    //            os.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    输出结果:

    我是媒婆,我要给你找对象,现在已经确认你的需求
    开始物色
    高富帅
    身高180cm
    有6块腹肌
    OK的话,准备办事

    反编译动态生成出来的$Proxy0.class文件,代码如下:

    // Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
    // Jad home page: http://www.kpdus.com/jad.html
    // Decompiler options: packimports(3) 
    
    import com.gupaoedu.vip.pattern.proxy.Person;
    import java.lang.reflect.*;
    
    public final class $Proxy0 extends Proxy
        implements Person
    {
    
        public $Proxy0(InvocationHandler invocationhandler)
        {
            super(invocationhandler);
        }
    
        public final boolean equals(Object obj)
        {
            try
            {
                return ((Boolean)super.h.invoke(this, m1, new Object[] {
                    obj
                })).booleanValue();
            }
            catch(Error _ex) { }
            catch(Throwable throwable)
            {
                throw new UndeclaredThrowableException(throwable);
            }
        }
    
        public final void findLove()
        {
            try
            {
                super.h.invoke(this, m3, null);
                return;
            }
            catch(Error _ex) { }
            catch(Throwable throwable)
            {
                throw new UndeclaredThrowableException(throwable);
            }
        }
    
        public final String toString()
        {
            try
            {
                return (String)super.h.invoke(this, m2, null);
            }
            catch(Error _ex) { }
            catch(Throwable throwable)
            {
                throw new UndeclaredThrowableException(throwable);
            }
        }
    
        public final int hashCode()
        {
            try
            {
                return ((Integer)super.h.invoke(this, m0, null)).intValue();
            }
            catch(Error _ex) { }
            catch(Throwable throwable)
            {
                throw new UndeclaredThrowableException(throwable);
            }
        }
    
        private static Method m1;
        private static Method m3;
        private static Method m2;
        private static Method m0;
    
        static 
        {
            try
            {
                m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
                    Class.forName("java.lang.Object")
                });
                m3 = Class.forName("com.gupaoedu.vip.pattern.proxy.Person").getMethod("findLove", new Class[0]);
                m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
                m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
            }
            catch(NoSuchMethodException nosuchmethodexception)
            {
                throw new NoSuchMethodError(nosuchmethodexception.getMessage());
            }
            catch(ClassNotFoundException classnotfoundexception)
            {
                throw new NoClassDefFoundError(classnotfoundexception.getMessage());
            }
        }
    }
    

    2.2CGlib动态代理

    UML类结构图:

    代码实现:

    Customer类

    public class Customer {
        public void findLove() {
            System.out.println("儿子要求:肤白貌美大长腿");
        }
    }

    CGlibMeipo类

    public class CGlibMeipo implements MethodInterceptor {
    
        public Object getInstance(Class<?> clazz) throws Exception {
            // 相当于Proxy,代理的工具类
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(clazz);
            enhancer.setCallback(this);
            return enhancer.create();
        }
    
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            before();
            Object obj = methodProxy.invokeSuper(o, objects);
            after();
            return obj;
        }
    
        private void before() {
            System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求");
            System.out.println("开始物色");
        }
    
        private void after() {
            System.out.println("OK的话,准备办事");
        }
    }

    测试代码:

    public class CGlibTest {
        public static void main(String[] args) {
            try {
    
                // JDK是采用读取接口的信息
                // CGlib是采用覆盖父类方法
                // 目的:都是生成一个新的类,去实现增强代码逻辑的功能
    
                // JDK Proxy 对于用户而言,必须要有一个接口实现,目标类相对来说复杂
                // CGlib 可以代理任意一个普通的类,没有任何要求
    
                // CGlib 生成代理逻辑更复杂,效率低,
                // 但是调用效率更高,因为生成了一个包含了所有逻辑的FastClass,不再需要发射调用
                // JDK Proxy生成代理的逻辑简单,执行效率相对要低,每次都要反射动态调用
    
                // CGlib 有个坑,CGlib不能代理final的方法
    
                System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E://cglib_proxy_classes");
    
                Customer obj = (Customer) new CGlibMeipo().getInstance(Customer.class);
                System.out.println(obj);
                obj.findLove();
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    }

    输出结果:

    我是媒婆,我要给你找对象,现在已经确认你的需求
    开始物色
    我是媒婆,我要给你找对象,现在已经确认你的需求
    开始物色
    OK的话,准备办事
    OK的话,准备办事
    com.gupaoedu.vip.pattern.proxy.dynamicproxy.cglibproxy.Customer$$EnhancerByCGLIB$$2436ded2@73c6c3b2
    我是媒婆,我要给你找对象,现在已经确认你的需求
    开始物色
    儿子要求:肤白貌美大长腿
    OK的话,准备办事

    3.静态代理和动态代理的区别:

    1.静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类。

    2.静态代理类事先知道要代理的是什么类,而动态代理类不知道要代理什么类,只有在运行时才知道。

    3.静态代理只能通过手动完成代理操作,如果被代理类增加新的方法,代理类需要同步新增,违背开闭原则。

       动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开闭原则。

    4.若动态代理要对目标类的增强逻辑扩展,结合策略模式,只需要新增策略类便可完成,无需修改代理类的代码。

    4.代理模式的优缺点

    优点:

    1.代理模式能将代理对象与真实被调用的目标对象分离。

    2.一定程度上降低了系统的耦合度,扩展性好。

    3.可以起到保护目标对象的作用。

    4.可以对目标对象的功能增强。

    缺点:

    1.代理模式会造成系统设计中类的数量增加。

    2.在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢。

    3.增加了系统的复杂度。

     

     

    展开全文
  • 设计模式—代理模式

    2017-05-02 13:26:00
    概念 代理模式(Proxy),为其它对象提供一种代理以控制对象的訪问。 模式结构 一个是真正的你要訪问的对象(目标),一个是...代理模式UML图 代码实战 <span style="font-family:KaiTi...
  • 设计模式之代理模式

    2016-09-29 13:46:00
    代理模式是一种结构型设计模式,它可以为其他对象...代理模式中的UML图如下: 代理模式中的角色: 1.抽象对象角色 声明了目标及代理对象的共同接口,这样在任何可以使用目标对象的地方都可以使用代理对象...
  • 文章目录一、代理设计模式组成分类静态代理UML结构图静态代理模式示例静态代理的局限性动态代理动态代理UML结构图Additional Thinking二、装饰设计模式三、二者异同 一、代理设计模式 组成 代理模式包含如下角色: ...
  • 老生常谈的问题,网上一搜一大把,但是不写下来,依然经常出现理解上的偏差,包括在实际的开发使用中,一些模式经常写串,因此将个人的一些理解写下来,争取做到言简意赅,能一句话...1,代理模式 UML实例: ...
  • 概述 代理模式(Proxy),为其他对象提供...代理模式UML图大致如下 角色 代理模式中含有的角色为 1)抽象对象(subject) 定义了目标对象(real subject)及代理对象(proxy)的共同接口,这样在任何使用
  • Day06代理模式

    2019-05-31 10:11:00
    代理模式是一种结构型设计模式,它可以为其他...代理模式中的UML图如下: 代理模式中的角色: 1.抽象对象角色 声明了目标及代理对象的共同接口,这样在任何可以使用目标对象的地方都可以使用代理对象。 2.目标对...
  • 代理模式(Proxy Pattern)

    2018-01-25 14:01:43
    代理模式属于设计模式中的结构型模式,有静态代理和动态代理两种实现方式。代理模式使用代理来控制访问委托中方法或者增强委托的功能。 2. 实现 静态代理 静态代理即是代理在编译期间已知。 UML类图 如上...
  • 结构型模式包括:代理模式、桥接模式、装饰器模式、适配器模式、门面模式、组合模式、享元模式。 简介 装饰模式(Decorator Pattern)主要解决继承过于复杂的问题,通过组合来替代继承;也就是说是继承关系的一种...
  • 之前说了代理模式,即为其他对象提供一种代理以控制对这个对象的访问,详情见《简说设计模式——代理模式》,而代理模式常见的...UML结构图如下:  这里以持久化层的数据交互为例,IUserDao是与数据库进行交...
  • 代理模式UML图: 简单结构示意: 为了保持行为的一致性,代理和委托通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理这中间一层,能有效控制对委托对象的直接访问,也可以很好地...
  • 代理模式: 为其他对象提供一种代理以控制对这个对象访问。 个人理解:一个通过共同的接口使用另外一个的属性方法,从而实现了对实际功能的保护。 类别:它是结构型设计模式的一种,主要处理的...
  • 代理模式(Proxy Pattern)中,一个代表另一个的功能。这种类型的设计模式属于结构型模式。 在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。 简而言之(其实已经够简短了吧),就两个点...
  • UML图,为了展示核心的代理模式类关系,这里细节的部分,比如Pursui和SchoolGirl的关系就不画了,代理模式的核心为代理和被代理实现的是同一个接口 代码结构 public class Client { public static void ...
  • UML结构图 基本代码的实现 Subject 抽象主体,定义一个request请求的抽象方法。 /** * @create on 2020/7/5 22:46 * @description 抽象主体 * @author mrdonkey */ abstract class Subject { abstract fun...
  • 代理模式(PROXY)介绍:代理模式也叫委托模式,日常生活中我们接触的最常见的就是代理上网。定义:为其他对像提供一种代理以控制对这个对象的访问。 使用场景:当无法或者不想直接访问某个对象或访问某个对象存在...
  • 代理模式代理模式(Proxy):为其他...UML结构如下: 代码实现: //定义一个Subject 抽象 public abstract class Subject { public abstract void Request(); } //定义一个RealSubjec...
  • 这章开始,我将讲下7种结构型模式:适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式。其中对象的适配器模式是各种模式的起源,我们看下面的 建议大家跟着画画uml图,方便大家理解 ...
  • 代理模式 定义: 为其他对象提供一种代理以控制对这个对象的访问 使用场景 ...代理模式UML结构图: Subject:抽象主题,声明真实主题与代理的共同接口方法。 RealSubject:真实主题,定义...
  • PROXY(代理模式

    2019-05-25 17:09:02
    代理模式为目标对象提供一种代理以控制对目标对象的访问,又叫Proxy或Surrogate。 类型 对象结构型模式 动机 对一个对象进行访问控制。 UML类图 时序 实现 主要角色 Proxy:代理 保存一个实体引用使得代理...
  • 1.1 代理模式UML图 1.2 日常生活中看代理模式 1.3 使用场景 1.4 java代码实现 2、JDK动态代理问题 2.1 为何调用代理的方法就会自动进入InvocationHandler 的 invoke()方法呢? 2.2 为什么被代理要实现...
  • 本书论述运用UML(统一建模语言)和模式进行对象建模的方法和技巧,重点讨论了如何使用面向对象的分析和设计技术来建造一个健壮的和易于维护的系统。 全书叙述清晰、图文并茂、实例丰富,是一部来自于大量经验的...
  • 代理模式的英 文叫做Proxy或Surrogate,它是一种对象结构型模式。 包含角色: Subject: 抽象主题角色 Proxy: 代理主题角色 RealSubject: 真实主题角色 UML图代理模式之很好理解的静态代理: 静态代理的实现:...

空空如也

空空如也

1 2 3 4 5 6
收藏数 102
精华内容 40
关键字:

代理模式uml类结构图