代理模式 订阅
代理模式(英语:Proxy Pattern)是程序设计中的一种设计模式。所谓的代理者是指一个类别可以作为其它东西的接口。代理者可以作任何东西的接口:网上连接、存储器中的大对象、文件或其它昂贵或无法复制的资源。 展开全文
代理模式(英语:Proxy Pattern)是程序设计中的一种设计模式。所谓的代理者是指一个类别可以作为其它东西的接口。代理者可以作任何东西的接口:网上连接、存储器中的大对象、文件或其它昂贵或无法复制的资源。
信息
示    例
引用计数
适用范围
程序设计
组成角色
抽象角色、代理角色、真实角色
中文名
代理模式
性    质
一种设计模式
外文名
Proxy Pattern
代理模式简介
代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。著名的代理模式例子为引用计数(英语:reference counting)指针对象。当一个复杂对象的多份副本须存在时,代理模式可以结合享元模式以减少存储器用量。典型作法是创建一个复杂对象及多个代理者,每个代理者会引用到原本的复杂对象。而作用在代理者的运算会转送到原本对象。一旦所有的代理者都不存在时,复杂对象会被移除。 [1] 
收起全文
精华内容
参与话题
问答
  • Java代理模式 动态代理 的应用场景

    万次阅读 2016-02-19 00:22:43
    先看一下代理模式,这个应该是设计模式中最简单的一个了,类图 ... Java动态代理其实内部也是通过Java反射机制来实现的,即已知的一个对象,然后在运行时动态调用其方法,这样在调用前后作一些相应的

    先看一下代理模式,这个应该是设计模式中最简单的一个了,类图

    代理模式类图

      代理模式最大的特点就是代理类和实际业务类实现同一个接口(或继承同一父类),代理对象持有一个实际对象的引用,外部调用时操作的是代理对象,而在代理对象的内部实现中又会去调用实际对象的操作

     Java动态代理其实内部也是通过Java反射机制来实现的,即已知的一个对象,然后在运行时动态调用其方法,这样在调用前后作一些相应的处理,这样说的比较笼统,举个简单的例子

       比如我们在应用中有这样一个需求,在对某个类的一个方法的调用前和调用后都要做一下日志操作,

    一个普通的接口

    [java] view plain copy
     print?
    1. public interface AppService {  
    2.       public boolean createApp(String name);  
    3. }  
     

    该接口的默认实现类

    [java] view plain copy
     print?
    1. public class AppServiceImpl implements AppService {  
    2.     public boolean createApp(String name) {  
    3.         System.out.println("App["+name+"] has been created.");  
    4.         return true;  
    5.     }  
    6. }  
     

    日志处理器

    [java] view plain copy
     print?
    1. public class LoggerInterceptor implements InvocationHandler {//注意实现这个Handler接口  
    2.     private Object target;//目标对象的引用,这里设计成Object类型,更具通用性  
    3.     public LoggerInterceptor(Object target){  
    4.         this.target = target;  
    5.     }  
    6.     public Object invoke(Object proxy, Method method, Object[] arg)  
    7.             throws Throwable {  
    8.         System.out.println("Entered "+target.getClass().getName()+"-"+method.getName()+",with arguments{"+arg[0]+"}");  
    9.         Object result = method.invoke(target, arg);//调用目标对象的方法  
    10.         System.out.println("Before return:"+result);  
    11.         return result;  
    12.     }  
    13. }  

    外部调用

    [java] view plain copy
     print?
    1. public class Main {  
    2.     public static void main(String[] args) {  
    3.         AppService target = new AppServiceImpl();//生成目标对象  
    4.         //接下来创建代理对象  
    5.         AppService proxy = (AppService) Proxy.newProxyInstance(  
    6.                 target.getClass().getClassLoader(),  
    7.                 target.getClass().getInterfaces(), new LoggerInterceptor(target));  
    8.         proxy.createApp("Kevin Test");  
    9.     }  
    10. }  
     此外,可以使用Spring AOP 。

    展开全文
  • 轻松学,Java 中的代理模式动态代理

    万次阅读 多人点赞 2017-06-29 22:08:55
    前几天我写了《秒懂,Java 注解 (Annotation)你可以这样学》,因为注解其实算反射技术中的一部分,然后我想了一下,反射技术中还有个常见的概念就是动态代理,于是索性再写一篇关于动态代理的博文好了。...

    前几天我写了《秒懂,Java 注解 (Annotation)你可以这样学》,因为注解其实算反射技术中的一部分,然后我想了一下,反射技术中还有个常见的概念就是动态代理,于是索性再写一篇关于动态代理的博文好了。

    我们先来分析代理这个词。

    代理

    代理是英文 Proxy 翻译过来的。我们在生活中见到过的代理,大概最常见的就是朋友圈中卖面膜的同学了。

    她们从厂家拿货,然后在朋友圈中宣传,然后卖给熟人。

    这里写图片描述

    按理说,顾客可以直接从厂家购买产品,但是现实生活中,很少有这样的销售模式。一般都是厂家委托给代理商进行销售,顾客跟代理商打交道,而不直接与产品实际生产者进行关联。

    所以,代理就有一种中间人的味道。

    接下来,我们说说软件中的代理模式。

    代理模式

    代理模式是面向对象编程中比较常见的设计模式。
    这里写图片描述

    这是常见代理模式常见的 UML 示意图。

    需要注意的有下面几点:

    1. 用户只关心接口功能,而不在乎谁提供了功能。上图中接口是 Subject。
    2. 接口真正实现者是上图的 RealSubject,但是它不与用户直接接触,而是通过代理。
    3. 代理就是上图中的 Proxy,由于它实现了 Subject 接口,所以它能够直接与用户接触。
    4. 用户调用 Proxy 的时候,Proxy 内部调用了 RealSubject。所以,Proxy 是中介者,它可以增强 RealSubject 操作。

    如果难于理解的话,我用事例说明好了。值得注意的是,代理可以分为静态代理和动态代理两种。先从静态代理讲起。

    静态代理

    我们平常去电影院看电影的时候,在电影开始的阶段是不是经常会放广告呢?

    电影是电影公司委托给影院进行播放的,但是影院可以在播放电影的时候,产生一些自己的经济收益,比如卖爆米花、可乐等,然后在影片开始结束时播放一些广告。

    现在用代码来进行模拟。

    首先得有一个接口,通用的接口是代理模式实现的基础。这个接口我们命名为 Movie,代表电影播放的能力。

    
    package com.frank.test;
    
    public interface Movie {
    	void play();
    }
    
    

    然后,我们要有一个真正的实现这个 Movie 接口的类,和一个只是实现接口的代理类。

    package com.frank.test;
    
    public class RealMovie implements Movie {
    
    	@Override
    	public void play() {
    		// TODO Auto-generated method stub
    		System.out.println("您正在观看电影 《肖申克的救赎》");
    	}
    
    }
    

    这个表示真正的影片。它实现了 Movie 接口,play() 方法调用时,影片就开始播放。那么 Proxy 代理呢?

    package com.frank.test;
    
    public class Cinema implements Movie {
    	
    	RealMovie movie;
    	
    	public Cinema(RealMovie movie) {
    		super();
    		this.movie = movie;
    	}
    
    
    	@Override
    	public void play() {
    		
    		guanggao(true);
    		
    		movie.play();
    		
    		guanggao(false);
    	}
    	
    	public void guanggao(boolean isStart){
    		if ( isStart ) {
    			System.out.println("电影马上开始了,爆米花、可乐、口香糖9.8折,快来买啊!");
    		} else {
    			System.out.println("电影马上结束了,爆米花、可乐、口香糖9.8折,买回家吃吧!");
    		}
    	}
    
    }
    
    

    Cinema 就是 Proxy 代理对象,它有一个 play() 方法。不过调用 play() 方法时,它进行了一些相关利益的处理,那就是广告。现在,我们编写测试代码。

    package com.frank.test;
    
    public class ProxyTest {
    
    	public static void main(String[] args) {
    		
    		RealMovie realmovie = new RealMovie();
    		
    		Movie movie = new Cinema(realmovie);
    		
    		movie.play();
    
    	}
    
    }
    
    

    然后观察结果:

    电影马上开始了,爆米花、可乐、口香糖9.8折,快来买啊!
    您正在观看电影 《肖申克的救赎》
    电影马上结束了,爆米花、可乐、口香糖9.8折,买回家吃吧!
    
    

    现在可以看到,代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。值得注意的是,代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。

    上面介绍的是静态代理的内容,为什么叫做静态呢?因为它的类型是事先预定好的,比如上面代码中的 Cinema 这个类。下面要介绍的内容就是动态代理。

    动态代理

    既然是代理,那么它与静态代理的功能与目的是没有区别的,唯一有区别的就是动态与静态的差别。

    那么在动态代理的中这个动态体现在什么地方?

    上一节代码中 Cinema 类是代理,我们需要手动编写代码让 Cinema 实现 Movie 接口,而在动态代理中,我们可以让程序在运行的时候自动在内存中创建一个实现 Movie 接口的代理,而不需要去定义 Cinema 这个类。这就是它被称为动态的原因。

    也许概念比较抽象。现在实例说明一下情况。

    假设有一个大商场,商场有很多的柜台,有一个柜台卖茅台酒。我们进行代码的模拟。

    package com.frank.test;
    
    public interface SellWine {
    	
    	 void mainJiu();
    
    }
    

    SellWine 是一个接口,你可以理解它为卖酒的许可证。

    package com.frank.test;
    
    public class MaotaiJiu implements SellWine {
    
    	@Override
    	public void mainJiu() {
    		// TODO Auto-generated method stub
    		System.out.println("我卖得是茅台酒。");
    
    	}
    
    }
    
    

    然后创建一个类 MaotaiJiu,对的,就是茅台酒的意思。

    我们还需要一个柜台来卖酒:

    package com.frank.test;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    
    public class GuitaiA implements InvocationHandler {
    	
    	private Object pingpai;
    	
    	
    	public GuitaiA(Object pingpai) {
    		this.pingpai = pingpai;
    	}
    
    
    
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args)
    			throws Throwable {
    		// TODO Auto-generated method stub
    		System.out.println("销售开始  柜台是: "+this.getClass().getSimpleName());
    		method.invoke(pingpai, args);
    		System.out.println("销售结束");
    		return null;
    	}
    
    }
    
    

    GuitaiA 实现了 InvocationHandler 这个类,这个类是什么意思呢?大家不要慌张,待会我会解释。

    然后,我们就可以卖酒了。

    package com.frank.test;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    
    
    public class Test {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		
    		MaotaiJiu maotaijiu = new MaotaiJiu();
    		
    		
    		InvocationHandler jingxiao1 = new GuitaiA(maotaijiu);
    
    		
    		SellWine dynamicProxy = (SellWine) Proxy.newProxyInstance(MaotaiJiu.class.getClassLoader(),
    				MaotaiJiu.class.getInterfaces(), jingxiao1);
    	
    		dynamicProxy.mainJiu();
    			
    	}
    
    }
    
    
    

    这里,我们又接触到了一个新的概念,没有关系,先别管,先看结果。

    销售开始  柜台是: GuitaiA
    我卖得是茅台酒。
    销售结束
    
    

    看到没有,我并没有像静态代理那样为 SellWine 接口实现一个代理类,但最终它仍然实现了相同的功能,这其中的差别,就是之前讨论的动态代理所谓“动态”的原因。

    动态代理语法

    放轻松,下面我们开始讲解语法,语法非常简单。

    动态代码涉及了一个非常重要的类 Proxy。正是通过 Proxy 的静态方法 newProxyInstance 才会动态创建代理。

    Proxy

    public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
    
    

    下面讲解它的 3 个参数意义。

    • loader 自然是类加载器
    • interfaces 代码要用来代理的接口
    • h 一个 InvocationHandler 对象

    初学者应该对于 InvocationHandler 很陌生,我马上就讲到这一块。

    InvocationHandler

    InvocationHandler 是一个接口,官方文档解释说,每个代理的实例都有一个与之关联的 InvocationHandler 实现类,如果代理的方法被调用,那么代理便会通知和转发给内部的 InvocationHandler 实现类,由它决定处理。

    public interface InvocationHandler {
    
        public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable;
    }
    
    

    InvocationHandler 内部只是一个 invoke() 方法,正是这个方法决定了怎么样处理代理传递过来的方法调用。

    • proxy 代理对象
    • method 代理对象调用的方法
    • args 调用的方法中的参数

    因为,Proxy 动态产生的代理会调用 InvocationHandler 实现类,所以 InvocationHandler 是实际执行者。

    public class GuitaiA implements InvocationHandler {
    	
    	private Object pingpai;
    	
    	
    	public GuitaiA(Object pingpai) {
    		this.pingpai = pingpai;
    	}
    
    
    
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args)
    			throws Throwable {
    		// TODO Auto-generated method stub
    		System.out.println("销售开始  柜台是: "+this.getClass().getSimpleName());
    		method.invoke(pingpai, args);
    		System.out.println("销售结束");
    		return null;
    	}
    
    }
    
    

    GuitaiA 就是实际上卖酒的地方。

    现在,我们加大难度,我们不仅要卖茅台酒,还想卖五粮液

    package com.frank.test;
    
    public class Wuliangye implements SellWine {
    
    	@Override
    	public void mainJiu() {
    		// TODO Auto-generated method stub
    		System.out.println("我卖得是五粮液。");
    
    	}
    
    }
    
    

    Wuliangye 这个类也实现了 SellWine 这个接口,说明它也拥有卖酒的许可证,同样把它放到 GuitaiA 上售卖。

    public class Test {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		
    		MaotaiJiu maotaijiu = new MaotaiJiu();
    		
    		Wuliangye wu = new Wuliangye();
    		
    		InvocationHandler jingxiao1 = new GuitaiA(maotaijiu);
    		InvocationHandler jingxiao2 = new GuitaiA(wu);
    		
    		SellWine dynamicProxy = (SellWine) Proxy.newProxyInstance(MaotaiJiu.class.getClassLoader(),
    				MaotaiJiu.class.getInterfaces(), jingxiao1);
    		SellWine dynamicProxy1 = (SellWine) Proxy.newProxyInstance(MaotaiJiu.class.getClassLoader(),
    				MaotaiJiu.class.getInterfaces(), jingxiao2);
    		
    		dynamicProxy.mainJiu();
    		
    		dynamicProxy1.mainJiu();
    		
    	}
    
    }
    
    

    我们来看结果:

    销售开始  柜台是: GuitaiA
    我卖得是茅台酒。
    销售结束
    销售开始  柜台是: GuitaiA
    我卖得是五粮液。
    销售结束
    
    

    有人会问,dynamicProxy 和 dynamicProxy1 什么区别没有?他们都是动态产生的代理,都是售货员,都拥有卖酒的技术证书。

    我现在扩大商场的经营,除了卖酒之外,还要卖烟。

    首先,同样要创建一个接口,作为卖烟的许可证。

    package com.frank.test;
    
    public interface SellCigarette {
    	void sell();
    }
    
    

    然后,卖什么烟呢?我是湖南人,那就芙蓉王好了。

    public class Furongwang implements SellCigarette {
    
    	@Override
    	public void sell() {
    		// TODO Auto-generated method stub
    		System.out.println("售卖的是正宗的芙蓉王,可以扫描条形码查证。");
    	}
    
    }
    
    

    然后再次测试验证:

    package com.frank.test;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    
    
    public class Test {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		
    		MaotaiJiu maotaijiu = new MaotaiJiu();
    		
    		Wuliangye wu = new Wuliangye();
    		
    		Furongwang fu = new Furongwang();
    		
    		InvocationHandler jingxiao1 = new GuitaiA(maotaijiu);
    		InvocationHandler jingxiao2 = new GuitaiA(wu);
    		
    		InvocationHandler jingxiao3 = new GuitaiA(fu);
    		
    		SellWine dynamicProxy = (SellWine) Proxy.newProxyInstance(MaotaiJiu.class.getClassLoader(),
    				MaotaiJiu.class.getInterfaces(), jingxiao1);
    		SellWine dynamicProxy1 = (SellWine) Proxy.newProxyInstance(MaotaiJiu.class.getClassLoader(),
    				MaotaiJiu.class.getInterfaces(), jingxiao2);
    		
    		dynamicProxy.mainJiu();
    		
    		dynamicProxy1.mainJiu();
    		
    		SellCigarette dynamicProxy3 = (SellCigarette) Proxy.newProxyInstance(Furongwang.class.getClassLoader(),
    				Furongwang.class.getInterfaces(), jingxiao3);
    		
    		dynamicProxy3.sell();
    		
    	}
    
    }
    
    

    然后,查看结果:

    销售开始  柜台是: GuitaiA
    我卖得是茅台酒。
    销售结束
    销售开始  柜台是: GuitaiA
    我卖得是五粮液。
    销售结束
    销售开始  柜台是: GuitaiA
    售卖的是正宗的芙蓉王,可以扫描条形码查证。
    销售结束
    
    
    

    结果符合预期。大家仔细观察一下代码,同样是通过 Proxy.newProxyInstance() 方法,却产生了 SellWine 和 SellCigarette 两种接口的实现类代理,这就是动态代理的魔力。

    动态代理的秘密

    一定有同学对于为什么 Proxy 能够动态产生不同接口类型的代理感兴趣,我的猜测是肯定通过传入进去的接口然后通过反射动态生成了一个接口实例。
    比如 SellWine 是一个接口,那么 Proxy.newProxyInstance() 内部肯定会有

    
    new SellWine();
    

    这样相同作用的代码,不过它是通过反射机制创建的。那么事实是不是这样子呢?直接查看它们的源码好了。需要说明的是,我当前查看的源码是 1.8 版本。

    public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {
            Objects.requireNonNull(h);
    
            final Class<?>[] intfs = interfaces.clone();
    
    
            /*
             * Look up or generate the designated proxy class.
             */
            Class<?> cl = getProxyClass0(loader, intfs);
    
            /*
             * Invoke its constructor with the designated invocation handler.
             */
            try {
    
    
                final Constructor<?> cons = cl.getConstructor(constructorParams);
                final InvocationHandler ih = h;
                if (!Modifier.isPublic(cl.getModifiers())) {
                    AccessController.doPrivileged(new PrivilegedAction<Void>() {
                        public Void run() {
                            cons.setAccessible(true);
                            return null;
                        }
                    });
                }
    
                return cons.newInstance(new Object[]{h});
    
            } catch (IllegalAccessException|InstantiationException e) {
                throw new InternalError(e.toString(), e);
            } catch (InvocationTargetException e) {
                Throwable t = e.getCause();
                if (t instanceof RuntimeException) {
                    throw (RuntimeException) t;
                } else {
                    throw new InternalError(t.toString(), t);
                }
            } catch (NoSuchMethodException e) {
                throw new InternalError(e.toString(), e);
            }
        }
    
    
    

    newProxyInstance 的确创建了一个实例,它是通过 cl 这个 Class 文件的构造方法反射生成。cl 由 getProxyClass0() 方法获取。

    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }
    
        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        return proxyClassCache.get(loader, interfaces);
    }
    
    

    直接通过缓存获取,如果获取不到,注释说会通过 ProxyClassFactory 生成。

    /**
         * A factory function that generates, defines and returns the proxy class given
         * the ClassLoader and array of interfaces.
         */
        private static final class ProxyClassFactory
            implements BiFunction<ClassLoader, Class<?>[], Class<?>>
        {
            // Proxy class 的前缀是 “$Proxy”,
            private static final String proxyClassNamePrefix = "$Proxy";
    
            // next number to use for generation of unique proxy class names
            private static final AtomicLong nextUniqueNumber = new AtomicLong();
    
            @Override
            public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
    
                Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
                for (Class<?> intf : interfaces) {
                    /*
                     * Verify that the class loader resolves the name of this
                     * interface to the same Class object.
                     */
                    Class<?> interfaceClass = null;
                    try {
                        interfaceClass = Class.forName(intf.getName(), false, loader);
                    } catch (ClassNotFoundException e) {
                    }
                    if (interfaceClass != intf) {
                        throw new IllegalArgumentException(
                            intf + " is not visible from class loader");
                    }
                    /*
                     * Verify that the Class object actually represents an
                     * interface.
                     */
                    if (!interfaceClass.isInterface()) {
                        throw new IllegalArgumentException(
                            interfaceClass.getName() + " is not an interface");
                    }
                    /*
                     * Verify that this interface is not a duplicate.
                     */
                    if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                        throw new IllegalArgumentException(
                            "repeated interface: " + interfaceClass.getName());
                    }
                }
    
                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.
                 */
                for (Class<?> intf : interfaces) {
                    int flags = intf.getModifiers();
                    if (!Modifier.isPublic(flags)) {
                        accessFlags = Modifier.FINAL;
                        String name = intf.getName();
                        int n = name.lastIndexOf('.');
                        String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                        if (proxyPkg == null) {
                            proxyPkg = pkg;
                        } else if (!pkg.equals(proxyPkg)) {
                            throw new IllegalArgumentException(
                                "non-public interfaces from different packages");
                        }
                    }
                }
    
                if (proxyPkg == null) {
                    // if no non-public proxy interfaces, use com.sun.proxy package
                    proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
                }
    
                /*
                 * Choose a name for the proxy class to generate.
                 */
                long num = nextUniqueNumber.getAndIncrement();
                String proxyName = proxyPkg + proxyClassNamePrefix + num;
    
                /*
                 * Generate the specified proxy class.
                 */
                byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                    proxyName, interfaces, accessFlags);
                try {
                    return defineClass0(loader, proxyName,
                                        proxyClassFile, 0, proxyClassFile.length);
                } 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());
                }
            }
        }
    
    
    

    这个类的注释说,通过指定的 ClassLoader 和 接口数组 用工厂方法生成 proxy class。 然后这个 proxy class 的名字是:

    
    // Proxy class 的前缀是 “$Proxy”,
    private static final String proxyClassNamePrefix = "$Proxy";
    
    long num = nextUniqueNumber.getAndIncrement();
    
    String proxyName = proxyPkg + proxyClassNamePrefix + num;
    
    

    所以,动态生成的代理类名称是包名+$Proxy+id序号

    生成的过程,核心代码如下:

    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                    proxyName, interfaces, accessFlags);
    
             
    return defineClass0(loader, proxyName,
                        proxyClassFile, 0, proxyClassFile.length);
    
    

    这两个方法,我没有继续追踪下去,defineClass0() 甚至是一个 native 方法。我们只要知道,动态创建代理这回事就好了。

    现在我们还需要做一些验证,我要检测一下动态生成的代理类的名字是不是包名+$Proxy+id序号

    public class Test {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		
    		MaotaiJiu maotaijiu = new MaotaiJiu();
    		
    		Wuliangye wu = new Wuliangye();
    		
    		Furongwang fu = new Furongwang();
    		
    		InvocationHandler jingxiao1 = new GuitaiA(maotaijiu);
    		InvocationHandler jingxiao2 = new GuitaiA(wu);
    		
    		InvocationHandler jingxiao3 = new GuitaiA(fu);
    		
    		SellWine dynamicProxy = (SellWine) Proxy.newProxyInstance(MaotaiJiu.class.getClassLoader(),
    				MaotaiJiu.class.getInterfaces(), jingxiao1);
    		SellWine dynamicProxy1 = (SellWine) Proxy.newProxyInstance(MaotaiJiu.class.getClassLoader(),
    				MaotaiJiu.class.getInterfaces(), jingxiao2);
    		
    		dynamicProxy.mainJiu();
    		
    		dynamicProxy1.mainJiu();
    		
    		SellCigarette dynamicProxy3 = (SellCigarette) Proxy.newProxyInstance(Furongwang.class.getClassLoader(),
    				Furongwang.class.getInterfaces(), jingxiao3);
    		
    		dynamicProxy3.sell();
    		
    		System.out.println("dynamicProxy class name:"+dynamicProxy.getClass().getName());
    		System.out.println("dynamicProxy1 class name:"+dynamicProxy1.getClass().getName());
    		System.out.println("dynamicProxy3 class name:"+dynamicProxy3.getClass().getName());
    		
    	}
    
    }
    
    

    结果如下:

    销售开始  柜台是: GuitaiA
    我卖得是茅台酒。
    销售结束
    销售开始  柜台是: GuitaiA
    我卖得是五粮液。
    销售结束
    销售开始  柜台是: GuitaiA
    售卖的是正宗的芙蓉王,可以扫描条形码查证。
    销售结束
    
    dynamicProxy class name:com.sun.proxy.$Proxy0
    dynamicProxy1 class name:com.sun.proxy.$Proxy0
    dynamicProxy3 class name:com.sun.proxy.$Proxy1
    
    

    SellWine 接口的代理类名是:com.sun.proxy.$Proxy0
    SellCigarette 接口的代理类名是:com.sun.proxy.$Proxy1

    这说明动态生成的 proxy class 与 Proxy 这个类同一个包。

    下面用一张图让大家记住动态代理涉及到的角色。
    这里写图片描述
    红框中 $Proxy0就是通过 Proxy 动态生成的。
    $Proxy0实现了要代理的接口。
    $Proxy0通过调用 InvocationHandler来执行任务。

    代理的作用

    可能有同学会问,已经学习了代理的知识,但是,它们有什么用呢?

    主要作用,还是在不修改被代理对象的源码上,进行功能的增强。

    这在 AOP 面向切面编程领域经常见。

    在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

    主要功能
    日志记录,性能统计,安全控制,事务处理,异常处理等等。

    上面的引用是百度百科对于 AOP 的解释,至于,如何通过代理来进行日志记录功能、性能统计等等,这个大家可以参考 AOP 的相关源码,然后仔细琢磨。

    同注解一样,很多同学可能会有疑惑,我什么时候用代理呢?

    这取决于你自己想干什么。你已经学会了语法了,其他的看业务需求。对于实现日志记录功能的框架来说,正合适。

    至此,静态代理和动态代理者讲完了。

    总结

    1. 代理分为静态代理和动态代理两种。
    2. 静态代理,代理类需要自己编写代码写成。
    3. 动态代理,代理类通过 Proxy.newInstance() 方法生成。
    4. 不管是静态代理还是动态代理,代理与被代理者都要实现两样接口,它们的实质是面向接口编程。
    5. 静态代理和动态代理的区别是在于要不要开发者自己定义 Proxy 类。
    6. 动态代理通过 Proxy 动态生成 proxy class,但是它也指定了一个 InvocationHandler 的实现类。
    7. 代理模式本质上的目的是为了增强现有代码的功能。

    读者们都在下面的二维码所示的免费的知识星球问我问题:
    在这里插入图片描述

    展开全文
  • /// 装饰器模式实现静态代理 /// AOP 在方法前后增加自定义的方法 /// </summary> public class DecoratorAOP { public static void Show() { User user = new User() { Name = "看看看看", Password = ...

    一:装饰器实现AOP

    /// <summary>
    /// 装饰器模式实现静态代理
    /// AOP 在方法前后增加自定义的方法
    /// </summary>
    public class DecoratorAOP
    {
        public static void Show()
        {
            User user = new User()
            {
                Name = "看看看看",
                Password = "123123123123"
            };
            IUserProcessor processor = new UserProcessor();
            processor.RegUser(user);
            Console.WriteLine("***************");
    
            processor = new UserProcessorDecorator(processor);
            processor.RegUser(user);
        }
    
        public interface IUserProcessor
        {
            void RegUser(User user);
        }
        public class UserProcessor : IUserProcessor
        {
            public void RegUser(User user)
            {
                Console.WriteLine("用户已注册。Name:{0},PassWord:{1}", user.Name, user.Password);
            }
        }
        /// <summary>
        /// 装饰器的模式去提供一个AOP功能
        /// </summary>
        public class UserProcessorDecorator : IUserProcessor
        {
            private IUserProcessor _UserProcessor { get; set; }
            public UserProcessorDecorator(IUserProcessor userprocessor)
            {
                this._UserProcessor = userprocessor;
            }
    
            public void RegUser(User user)
            {
                BeforeProceed(user);
    
                this._UserProcessor.RegUser(user);
    
                AfterProceed(user);
            }
    
            /// <summary>
            /// 业务逻辑之前
            /// </summary>
            /// <param name="user"></param>
            private void BeforeProceed(User user)
            {
                Console.WriteLine("方法执行前");
            }
            /// <summary>
            /// 业务逻辑之后
            /// </summary>
            /// <param name="user"></param>
            private void AfterProceed(User user)
            {
                Console.WriteLine("方法执行后");
            }
        }
    }
    

    二:代理模式实现AOP

     /// <summary>
        /// 代理模式实现静态代理
        /// AOP 在方法前后增加自定义的方法
        /// </summary>
        public class ProxyAOP
        {
            public static void Show()
            {
                User user = new User()
                {
                    Name = "哈哈哈哈",
                    Password = "123123123123"
                };
                IUserProcessor processor = new UserProcessor();
                processor.RegUser(user);
                Console.WriteLine("***************");
    
                processor = new ProxyUserProcessor();
                processor.RegUser(user);
            }
    
            public interface IUserProcessor
            {
                void RegUser(User user);
            }
            public class UserProcessor : IUserProcessor
            {
                public void RegUser(User user)
                {
                    Console.WriteLine("用户已注册。Name:{0},PassWord:{1}", user.Name, user.Password);
                }
            }
    
            /// <summary>
            /// 代理模式去提供一个AOP功能
            /// </summary>
            public class ProxyUserProcessor : IUserProcessor
            {
                private IUserProcessor _UserProcessor = new UserProcessor();
                public void RegUser(User user)
                {
                    BeforeProceed(user);
                    this._UserProcessor.RegUser(user);
                    AfterProceed(user);
                }
    
                /// <summary>
                /// 业务逻辑之前
                /// </summary>
                /// <param name="user"></param>
                private void BeforeProceed(User user)
                {
                    Console.WriteLine("方法执行前");
                }
                /// <summary>
                /// 业务逻辑之后
                /// </summary>
                /// <param name="user"></param>
                private void AfterProceed(User user)
                {
                    Console.WriteLine("方法执行后");
                }
            }
    
        }
    
    

    三:使用.Net Remoting/RealProxy 真实代理实现AOP

    /// <summary>
        /// 使用.Net Remoting/RealProxy 实现动态代理
        /// 局限在业务类必须是继承自MarshalByRefObject类型
        /// </summary>
        public class RealProxyAOP
        {
            public static void Show()
            {
                User user = new User()
                {
                    Name = "换换换",
                    Password = "123456"
                };
    
                UserProcessor processor = new UserProcessor();
                processor.RegUser(user);
    
                Console.WriteLine("*********************");
                UserProcessor userProcessor = TransparentProxy.Create<UserProcessor>();
                userProcessor.RegUser(user);
            }
    
            /// <summary>
            /// 真实代理
            /// </summary>
            /// <typeparam name="T"></typeparam>
            public class MyRealProxy<T> : RealProxy
            {
                private T tTarget;
                public MyRealProxy(T target)
                    : base(typeof(T))
                {
                    this.tTarget = target;
                }
    
                public override IMessage Invoke(IMessage msg)
                {
                    BeforeProceede(msg);//Log  try-catch
    
                    IMethodCallMessage callMessage = (IMethodCallMessage)msg;
                    object returnValue = callMessage.MethodBase.Invoke(this.tTarget, callMessage.Args);
    
                    AfterProceede(msg);
    
                    return new ReturnMessage(returnValue, new object[0], 0, null, callMessage);
                }
                public void BeforeProceede(IMessage msg)
                {
                    Console.WriteLine("方法执行前可以加入的逻辑");
                }
                public void AfterProceede(IMessage msg)
                {
                    Console.WriteLine("方法执行后可以加入的逻辑");
                }
            }
    
            /// <summary>
            /// 透明代理
            /// </summary>
            public static class TransparentProxy
            {
                public static T Create<T>()
                {
                    T instance = Activator.CreateInstance<T>();
                    MyRealProxy<T> realProxy = new MyRealProxy<T>(instance);
                    T transparentProxy = (T)realProxy.GetTransparentProxy();
                    return transparentProxy;
                }
            }
    
    
            public interface IUserProcessor
            {
                void RegUser(User user);
            }
    
            /// <summary>
            /// 必须继承自MarshalByRefObject父类,否则无法生成
            /// </summary>
            public class UserProcessor : MarshalByRefObject, IUserProcessor
            {
                public void RegUser(User user)
                {
                    Console.WriteLine("用户已注册。用户名称{0} Password{1}", user.Name, user.Password);
                }
            }
    
        }
    
    

    四:使用Castle\DynamicProxy 动态代理实现AOP

    /// <summary>
        /// 使用Castle\DynamicProxy 实现动态代理
        /// 方法必须是虚方法
        /// </summary>
        public class CastleProxyAOP
        {
            public static void Show()
            {
                User user = new User()
                {
                    Name = "啦啦啦",
                    Password = "123456"
                };
                ProxyGenerator generator = new ProxyGenerator();
                MyInterceptor interceptor = new MyInterceptor();
                UserProcessor userprocessor = generator.CreateClassProxy<UserProcessor>(interceptor);
                userprocessor.RegUser(user);
            }
            public interface IUserProcessor
            {
                void RegUser(User user);
            }
    
            public class UserProcessor : IUserProcessor
            {
                /// <summary>
                /// 必须带上virtual 否则无效~
                /// </summary>
                /// <param name="user"></param>
                public virtual void RegUser(User user) 
                {
                    Console.WriteLine($"用户已注册。Name:{user.Name},PassWord:{user.Password}");
                }
            }
    
            public class MyInterceptor : IInterceptor
            {
                public void Intercept(IInvocation invocation)
                {
                    PreProceed(invocation);
                    invocation.Proceed();//就是调用原始业务方法
                    PostProceed(invocation);
                }
                public void PreProceed(IInvocation invocation)
                {
                    Console.WriteLine("方法执行前");
                }
    
                public void PostProceed(IInvocation invocation)
                {
                    Console.WriteLine("方法执行后");
                }
            }
        }
    
    

    五:使用EntLib\PIAB Unity 实现动态代理

    public class UnityAOP
        {
            public static void Show()
            {
                User user = new User()
                {
                    Name = "Unity",
                    Password = "1234567890123456789"
                };
                //-----------------------声明一个容器------------------------
                IUnityContainer container = new UnityContainer();
                //container.RegisterType<IUserProcessor, UserProcessor>();//声明UnityContainer并注册IUserProcessor
                //IUserProcessor processor = container.Resolve<IUserProcessor>();
                //processor.RegUser(user);
                //-----------------------添加并配置拦截器------------------------
                container.AddNewExtension<Interception>();
                container.RegisterType<IUserProcessor, UserProcessor>()
                .Configure<Interception>()
                    .SetInterceptorFor<IUserProcessor>(new InterfaceInterceptor());
    
    
                //映射类型
                IUserProcessor userprocessor = container.Resolve<IUserProcessor>();
    
                Console.WriteLine("********************");
                userprocessor.RegUser(user);//调用
                userprocessor.GetUser(user);//调用
            }
    
            #region 特性对应的行为
            public class UserHandler : ICallHandler
            {
                public int Order { get; set; }
                public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
                {
                    User user = input.Inputs[0] as User;
                    if (user.Password.Length < 10)
                    {
                        return input.CreateExceptionMethodReturn(new Exception("密码长度不能小于10位"));
                    }
                    Console.WriteLine("参数检测无误");
    
                    IMethodReturn methodReturn = getNext()(input, getNext);
                    return methodReturn;
                }
            }
    
            public class LogHandler : ICallHandler
            {
                public int Order { get; set; }
    
                public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
                {
                    User user = input.Inputs[0] as User;
                    string message = $"RegUser:Username:{user.Name},Password:{user.Password}";
                    Console.WriteLine("日志已记录,Message:{0},Ctime:{1}", message, DateTime.Now);
                    return getNext()(input, getNext);
                }
            }
    
    
            public class ExceptionHandler : ICallHandler
            {
                public int Order { get; set; }
                public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
                {
                    IMethodReturn methodReturn = getNext()(input, getNext);
                    if (methodReturn.Exception == null)
                    {
                        Console.WriteLine("无异常");
                    }
                    else
                    {
                        Console.WriteLine($"异常:{methodReturn.Exception.Message}");
                    }
                    return methodReturn;
                }
            }
    
            public class AfterLogHandler : ICallHandler
            {
                public int Order { get; set; }
                public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
                {
                    IMethodReturn methodReturn = getNext()(input, getNext);
                    User user = input.Inputs[0] as User;
                    string message = string.Format("RegUser:Username:{0},Password:{1}", user.Name, user.Password);
                    Console.WriteLine("完成日志,Message:{0},Ctime:{1},计算结果{2}", message, DateTime.Now, methodReturn.ReturnValue);
                    return methodReturn;
                }
            }
            #endregion 特性对应的行为
    
            #region 特性
            public class UserHandlerAttribute : HandlerAttribute
            {
                public override ICallHandler CreateHandler(IUnityContainer container)
                {
                    ICallHandler handler = new UserHandler() { Order = this.Order };
                    return handler;
                }
            }
    
            public class LogHandlerAttribute : HandlerAttribute
            {
                public override ICallHandler CreateHandler(IUnityContainer container)
                {
                    return new LogHandler() { Order = this.Order };
                }
            }
    
            public class ExceptionHandlerAttribute : HandlerAttribute
            {
                public override ICallHandler CreateHandler(IUnityContainer container)
                {
                    return new ExceptionHandler() { Order = this.Order };
                }
            }
    
            public class AfterLogHandlerAttribute : HandlerAttribute
            {
                public override ICallHandler CreateHandler(IUnityContainer container)
                {
                    return new AfterLogHandler() { Order = this.Order };
                }
            }
            #endregion 特性
    
            #region 业务
            [UserHandlerAttribute(Order = 1)]
            [ExceptionHandlerAttribute(Order = 3)]
            [LogHandlerAttribute(Order = 2)]
            [AfterLogHandlerAttribute(Order = 5)]
            public interface IUserProcessor
            {
                void RegUser(User user);
                User GetUser(User user);
            }
    
            public class UserProcessor : IUserProcessor
            {
                public void RegUser(User user)
                {
                    Console.WriteLine("用户已注册。");
                }
    
                public User GetUser(User user)
                {
                    return user;
                }
            }
            #endregion 业务
        }
    

    五:使用EntLib\PIAB Unity 读取配置文件方式实现动态代理

    第一步:使用Unity需要nuget引入6个包

    1. Unity
    2. Unity.Abstractions
    3. Unity.Configuration
    4. Unity.Container
    5. Unity.Interception
    6. Unity.Interception.Configuration

    第二步:固定写法

    public class UnityConfigAOP
        {
            public static void Show()
            {
                User user = new User()
                {
                    Name = "配置文件方式实现",
                    Password = "1234567890123456789"
                };
                //创建容器
                IUnityContainer container = new UnityContainer();
                //扩展配置文件映射
                ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
                fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "CfgFiles\\Unity.Config");
                //指向扩展配置文件
                Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
                //容器注入到UnityConfigurationSection中
                UnityConfigurationSection configSection = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);
                configSection.Configure(container, "aopContainer");
                //使用
                IUserProcessor processor = container.Resolve<IUserProcessor>();
                processor.RegUser(user);
                processor.GetUser(user);
            }
        }
    

    三:配置文件

    <configuration>
      <configSections>
        <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/>
        <!--Microsoft.Practices.Unity.Configuration.UnityConfigurationSection-->
      </configSections>
      <unity>
        <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration"/>
        <containers>
          <container name="aopContainer">
            <extension type="Interception"/>  
            <register type="MyAOP.UnityWay.IUserProcessor,MyAOP" mapTo="MyAOP.UnityWay.UserProcessor,MyAOP">
              <interceptor type="InterfaceInterceptor"/> 
              <interceptionBehavior type="MyAOP.UnityWay.MoniterBehavior, MyAOP"/>
              <interceptionBehavior type="MyAOP.UnityWay.LogBeforeBehavior, MyAOP"/>
              <interceptionBehavior type="MyAOP.UnityWay.ParameterCheckBehavior, MyAOP"/>
              <interceptionBehavior type="MyAOP.UnityWay.CachingBehavior, MyAOP"/>
              <interceptionBehavior type="MyAOP.UnityWay.ExceptionLoggingBehavior, MyAOP"/>
              <interceptionBehavior type="MyAOP.UnityWay.LogAfterBehavior, MyAOP"/> 
            </register>
          </container>
        </containers>
      </unity>
    </configuration>
    

    四:aop切面拦截器的类

    /// <summary>
        /// 不需要特性
        /// </summary>
        public class MoniterBehavior : IInterceptionBehavior
        {
            public IEnumerable<Type> GetRequiredInterfaces()
            {
                return Type.EmptyTypes;
            }
    
            public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
            {
                Stopwatch stopwatch = new Stopwatch();
                stopwatch.Start(); 
                // 可以在这儿添加方法之前的逻辑
                 
                var query = getNext().Invoke(input, getNext);
    
    
                stopwatch.Stop();
                Console.WriteLine($"执行耗时:{stopwatch.ElapsedMilliseconds} ms"); 
                return query; 
            }
    
            public bool WillExecute
            {
                get { return true; }
            }
        }
    
    public class LogBeforeBehavior : IInterceptionBehavior
        {
            public IEnumerable<Type> GetRequiredInterfaces()
            {
                return Type.EmptyTypes;
            }
    
            public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
            {
                Console.WriteLine("LogBeforeBehavior");
                foreach (var item in input.Inputs)
                {
                    Console.WriteLine(item.ToString());//反射获取更多信息
                }
                var query = getNext().Invoke(input, getNext);
    
                //下一个节点的方法已经执行完毕   
                //在这里计入方法执行后的逻辑
                return query;
    
                //现在是21:53 大家开始提问 && 休息  21:57 开始答疑!期间老师不说话
            }
    
            public bool WillExecute
            {
                get { return true; }
            }
        }
    
    public class ParameterCheckBehavior : IInterceptionBehavior
        {
            public IEnumerable<Type> GetRequiredInterfaces()
            {
                return Type.EmptyTypes;
            }
    
            public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
            {
                Console.WriteLine("ParameterCheckBehavior");
                //通过特性校验
                User user = input.Inputs[0] as User;
                if (user.Password.Length < 10)
                {
                    //throw new Exception(); 
                    return input.CreateExceptionMethodReturn(new Exception("密码长度不能小于10位"));
                }
                else
                {
                    Console.WriteLine("参数检测无误");
                    return getNext().Invoke(input, getNext);
                }
            }
    
            public bool WillExecute
            {
                get { return true; }
            }
        }
    
    public class CachingBehavior : IInterceptionBehavior
        {
            public IEnumerable<Type> GetRequiredInterfaces()
            {
                return Type.EmptyTypes;
            }
    
            public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
            {
                Console.WriteLine("CachingBehavior");
                //input.Target.GetType().GetCustomAttributes()
                if (input.MethodBase.Name.Equals("GetUser"))
                    return input.CreateMethodReturn(new User() { Id = 234, Name = "Richard" });
                return getNext().Invoke(input, getNext);
            }
    
            public bool WillExecute
            {
                get { return true; }
            }
        }
    
    public class ExceptionLoggingBehavior : IInterceptionBehavior
        {
            public IEnumerable<Type> GetRequiredInterfaces()
            {
                return Type.EmptyTypes;
            }
    
            public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
            {
                Console.WriteLine("ExceptionLoggingBehavior");
                IMethodReturn methodReturn = getNext()(input, getNext);
                if (methodReturn.Exception == null)
                {
                    Console.WriteLine("无异常");
                }
                else
                {
                    Console.WriteLine($"异常:{methodReturn.Exception.Message}");
                }
                return methodReturn;
            }
    
            public bool WillExecute
            {
                get { return true; }
            }
        }
    
    public class LogAfterBehavior : IInterceptionBehavior
        {
            public IEnumerable<Type> GetRequiredInterfaces()
            {
                return Type.EmptyTypes;
            }
    
    
            //一切正常的  刷个1
            public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
            {
                Console.WriteLine("LogAfterBehavior");
                foreach (var item in input.Inputs)
                {
                    Console.WriteLine(item.ToString());//反射获取更多信息
                }
                IMethodReturn methodReturn = getNext()(input, getNext);
                Console.WriteLine("LogAfterBehavior" + methodReturn.ReturnValue);
                return methodReturn;
            }
    
            public bool WillExecute
            {
                get { return true; }
            }
        }
    
    展开全文
  • 秒懂Java代理与动态代理模式

    万次阅读 多人点赞 2018-06-30 17:08:23
    什么是动态代理模式?二者什么关系?具体如何实现?什么原理?如何改进?这即为我们学习一项新知识的正确打开方式,我们接下来会以此展开,让你秒懂。 概念 什么是代理模式 定义:为其他对象提供一种代理以控制...

    版权申明】非商业目的可自由转载
    博文地址:https://blog.csdn.net/shusheng0007/article/details/80864854
    出自:shusheng007

    设计模式系列文章:
    秒懂设计模式之建造者模式(Builder Pattern)
    秒懂设计模式之简单工厂模式(Simple Factory Pattern)
    秒懂设计模式之工厂方法模式(Factory Method Pattern)
    秒懂设计模式之抽象工厂模式(Abstract Factory Pattern)

    概述

    什么是代理模式?解决什么问题(即为什么需要)?什么是静态代理?什么是动态代理模式?二者什么关系?具体如何实现?什么原理?如何改进?这即为我们学习一项新知识的正确打开方式,我们接下来会以此展开,让你秒懂。

    概念

    什么是代理模式

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

    定义总是抽象而晦涩难懂的,让我们回到生活中来吧。

    实例:王二狗公司(天津在线回声科技发展有限公司)老板突然在发工资的前一天带着小姨子跑路了,可怜二狗一身房贷,被迫提起劳动仲裁,劳动局就会为其指派一位代理律师全权负责二狗的仲裁事宜。那这里面就是使用了代理模式,因为在劳动仲裁这个活动中,代理律师会全权代理王二狗。

    解决什么问题

    下面是一些使用场景,不过太抽象,暂时可以不要在意,随着你的不断进步你终究会明白的。

    • 远程代理 :为位于两个不同地址空间对象的访问提供了一种实现机制,可以将一些消耗资源较多的对象和操作移至性能更好的计算机上,提高系统的整体运行效率。
    • 虚拟代理:通过一个消耗资源较少的对象来代表一个消耗资源较多的对象,可以在一定程度上节省系统的运行开销。
    • 缓冲代理:为某一个操作的结果提供临时的缓存存储空间,以便在后续使用中能够共享这些结果,优化系统性能,缩短执行时间。
    • 保护代理:可以控制对一个对象的访问权限,为不同用户提供不同级别的使用权限。
    • 智能引用:要为一个对象的访问(引用)提供一些额外的操作时可以使用

    什么是静态代理

    静态代理是指预先确定了代理与被代理者的关系,例如王二狗的代理律师方文镜是在开庭前就确定的了。那映射到编程领域的话,就是指代理类与被代理类的依赖关系在编译期间就确定了。下面就是王二狗劳动仲裁的代码实现:

    首先定义一个代表诉讼的接口

    public interface ILawSuit {
        void submit(String proof);//提起诉讼
        void defend();//法庭辩护
    }
    

    王二狗诉讼类型,实现ILawSuit接口

    public class SecondDogWang implements ILawSuit {
        @Override
        public void submit(String proof) {
            System.out.println(String.format("老板欠薪跑路,证据如下:%s",proof));
        }
    
        @Override
        public void defend() {
            System.out.println(String.format("铁证如山,%s还钱","马旭"));
        }
    }
    

    代理律师诉讼类,实现ILawSuit接口

    public class ProxyLawyer implements ILawSuit {
    
        ILawSuit plaintiff;//持有要代理的那个对象
        public ProxyLawyer(ILawSuit plaintiff) {
            this.plaintiff=plaintiff;
        }
    
        @Override
        public void submit(String proof) {
            plaintiff.submit(proof);
        }
    
        @Override
        public void defend() {
            plaintiff.defend();
        }
    }
    

    产生代理对象的静态代理工厂类

    public class ProxyFactory {
        public static ILawSuit getProxy(){
            return new ProxyLawyer(new SecondDogWang());
        }
    }
    

    这样就基本构建了静态代理关系了,然后在客户端就可以使用代理对象来进行操作了。

        public static void main(String[] args) {
            ProxyFactory.getProxy().submit("工资流水在此");
            ProxyFactory.getProxy().defend();
        }
    

    输出结果如下:

    老板欠薪跑路,证据如下:工资流水在此
    铁证如山,马旭还钱
    

    可以看到,代理律师全权代理了王二狗的本次诉讼活动。那使用这种代理模式有什么好处呢,我们为什么不直接让王二狗直接完成本次诉讼呢?现实中的情况比较复杂,但是我可以简单列出几条:这样代理律师就可以在提起诉讼等操作之前做一些校验工作,或者记录工作。例如二狗提供的资料,律师可以选择的移交给法庭而不是全部等等操作,就是说可以对代理的对做一些控制。例如二狗不能出席法庭,代理律师可以代为出席。。。

    什么是动态代理

    动态代理本质上仍然是代理,情况与上面介绍的完全一样,只是代理与被代理人的关系是动态确定的,例如王二狗的同事牛翠花开庭前没有确定她的代理律师,而是在开庭当天当庭选择了一个律师,映射到编程领域为这个关系是在运行时确定的。

    那既然动态代理没有为我们增强代理方面的任何功能,那我们为什么还要用动态代理呢,静态代理不是挺好的吗?凡是动态确定的东西大概都具有灵活性,强扩展的优势。上面的例子中如果牛翠花也使用静态代理的话,那么就需要再添加两个类。一个是牛翠花诉讼类,一个是牛翠花的代理律师类,还的在代理静态工厂中添加一个方法。而如果使用动态代理的话,就只需要生成一个诉讼类就可以了,全程只需要一个代理律师类,因为我们可以动态的将很多人的案子交给这个律师来处理。

    Jdk动态代理实现

    在java的动态代理机制中,有两个重要的类或接口,一个是InvocationHandler接口、另一个则是 Proxy类,这个类和接口是实现我们动态代理所必须用到的。

    InvocationHandler接口是给动态代理类实现的,负责处理被代理对象的操作的,而Proxy是用来创建动态代理类实例对象的,因为只有得到了这个对象我们才能调用那些需要代理的方法。

    接下来我们看下实例,牛翠花动态指定代理律师是如何实现的。
    1.构建一个牛翠花诉讼类

    public class CuiHuaNiu implements ILawSuit {
        @Override
        public void submit(String proof) {
            System.out.println(String.format("老板欠薪跑路,证据如下:%s",proof));
        }
        @Override
        public void defend() {
            System.out.println(String.format("铁证如山,%s还牛翠花血汗钱","马旭"));
        }
    }
    

    2.构建一个动态代理类

    public class DynProxyLawyer implements InvocationHandler {
        private Object target;//被代理的对象
        public DynProxyLawyer(Object obj){
            this.target=obj;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    	    System.out.println("案件进展:"+method.getName());
            Object result=method.invoke(target,args);
            return result;
        }
    }
    

    3.修改静态工厂方法

    public class ProxyFactory {
    	...
    
        public static Object getDynProxy(Object target) {
            InvocationHandler handler = new DynProxyLawyer(target);
            return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);
        }
    }
    

    4.客户端使用

        public static void main(String[] args) {
            ILawSuit proxy= (ILawSuit) ProxyFactory.getDynProxy(new CuiHuaNiu());
            proxy.submit("工资流水在此");
            proxy.defend();
        }
    

    输出结果为:

    案件进展:submit
    老板欠薪跑路,证据如下:工资流水在此
    案件进展:defend
    铁证如山,马旭还牛翠花血汗钱
    

    JDK动态代理实现的原理

    首先Jdk的动态代理实现方法是依赖于接口的,首先使用接口来定义好操作的规范。然后通过Proxy类产生的代理对象调用被代理对象的操作,而这个操作又被分发给InvocationHandler接口的 invoke方法具体执行

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
    

    此方法的参数含义如下
    proxy:代表动态代理对象
    method:代表正在执行的方法
    args:代表当前执行方法传入的实参
    返回值:表示当前执行方法的返回值

    例如上面牛翠花案例中,我们使用Proxy类的newProxyInstance()方法生成的代理对象proxy去调用了proxy.submit("工资流水在此");操作,那么系统就会将此方法分发给invoke().其中proxy对象的类是系统帮我们动态生产的,其实现了我们的业务接口ILawSuit

    cgLib的动态代理实现

    由于JDK只能针对实现了接口的类做动态代理,而不能对没有实现接口的类做动态代理,所以cgLib横空出世!CGLib(Code Generation Library)是一个强大、高性能的Code生成类库,它可以在程序运行期间动态扩展类或接口,它的底层是使用java字节码操作框架ASM实现。

    1 引入cgLib 库
    cglib-nodep-3.2.6.jar:使用nodep包不需要关联asm的jar包,jar包内部包含asm的类.

    2 定义业务类,被代理的类没有实现任何接口

    public class Frank {
       public void submit(String proof) {
           System.out.println(String.format("老板欠薪跑路,证据如下:%s",proof));
       }
       public void defend() {
           System.out.println(String.format("铁证如山,%s还Frank血汗钱","马旭"));
       }
    }
    

    3 定义拦截器,在调用目标方法时,CGLib会回调MethodInterceptor接口方法拦截,来实现你自己的代理逻辑,类似于JDK中的InvocationHandler接口。

    public class cgLibDynProxyLawyer implements MethodInterceptor {
        @Override
        public Object intercept(Object o, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {
            if (method.getName().equals("submit"))
                System.out.println("案件提交成功,证据如下:"+ Arrays.asList(params));
            Object result = methodProxy.invokeSuper(o, params);
            return result;
        }
    }
    

    4定义动态代理工厂,生成动态代理

    public class ProxyFactory {
        public static Object getGcLibDynProxy(Object target){
            Enhancer enhancer=new Enhancer();
            enhancer.setSuperclass(target.getClass());
            enhancer.setCallback(new cgLibDynProxyLawyer());
            Object targetProxy= enhancer.create();
            return targetProxy;
        }
    }
    

    5客户端调用

      public static void main(String[] args) {
            Frank cProxy= (Frank) ProxyFactory.getGcLibDynProxy(new Frank());
            cProxy.submit("工资流水在此");
            cProxy.defend();
        }
    

    输出结果:

    案件提交成功,证据如下:[工资流水在此]
    老板欠薪跑路,证据如下:工资流水在此
    铁证如山,马旭还Frank血汗钱
    

    可见,通过cgLib对没有实现任何接口的类做了动态代理,达到了和前面一样的效果。这里只是简单的讲解了一些cgLib的使用方式,有兴趣的可以进一步了解其比较高级的功能,例如回调过滤器(CallbackFilter)等。

    cgLib的动态代理原理

    CGLIB原理:动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。

    CGLIB底层:使用字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

    CGLIB缺点:对于final方法,无法进行代理。

    动态代理在AOP中的应用

    什么是AOP? 维基百科上如是说:

    定义:In computing, aspect-oriented programming (AOP) is a programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns.
    AOP是一种编程范式,其目标是通过隔离切面耦合来增加程序的模块化。

    首先声明,AOP是OOP的补充,其地位及其重要性远不及OOP,总体来说OOP面向名词领域而AOP面向动词领域,例如对一个人的设计肯定是使用OOP,例如这个人有手,脚,眼睛瞪属性。而对这个人上厕所这个动作就会涉及到AOP,例如上厕所前的先确定一下拿没拿手纸等。要理解AOP就首先要理解什么是切面耦合(cross-cutting concerns)。例如有这样一个需求,要求为一个程序中所有方法名称以test开头的方法打印一句log,这个行为就是一个典型的cross-cutting场景。首先这个打印log和业务毫无关系,然后其处于分散在整个程序当中的各个模块,如果按照我们原始的方法开发,一旦后期需求变动将是及其繁琐的。所以我们就需要将这个切面耦合封装隔离,不要将其混入业务代码当中。

    例如在王二狗的案子中,我们希望在案子起诉后打印一句成功的log,如果不使用代理的话,我们是需要将log写在相应的业务逻辑里面的,例如王二狗诉讼类SecondDogWang里面的submit()方法中。使用了动态代理后,我们只需要在InvocationHandler 里面的invoke()方法中写就可以了,不会侵入业务代码当中,在以后的维护过程中对业务毫无影响,这是我们希望看到的。

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals("submit"))
               System.out.println("案件提交成功,证据如下:"+ Arrays.asList(args));
        Object result=method.invoke(target,args);
        return result;
    }
    

    输出结果为:

    案件提交成功,证据如下:[工资流水在此]
    老板欠薪跑路,证据如下:工资流水在此
    铁证如山,马旭还牛翠花血汗钱
    

    所以AOP主要可以用于:日志记录,性能统计,安全控制,事务处理,异常处理等场景下。

    总结

    静态代理比动态代理更符合OOP原则,在日常开发中使用也较多。动态代理在开发框架时使用较多,例如大名鼎鼎的Spring

    最后希望王二狗和牛翠花他们可以顺利拿回自己的血汗钱。

    展开全文
  • 代理模式的使用总结

    万次阅读 多人点赞 2020-04-20 14:14:37
    一、代理模式 二、静态代理 (一)静态代理 (二)静态代理简单实现 三、动态代理 (一)动态代理 (二)动态代理简单实现 四、动态代理原理分析 五、InvocationHandler接口和Proxy类详解 六、JDK动态代理...
  • 代理模式动态代理模式

    千次阅读 多人点赞 2015-03-19 09:35:14
    1、代理模式 所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用。 代理模式给某...
  • 其实每个模式名称就表明了该模式的作用,代理模式就是多一个代理类出来,替原对象进行一些操作,比如我们在租房子的时候回去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你...
  • 在前一章“《学习笔记》之JAVA设计模式--代理模式(动态)(一)”中我们分别使用JDK自带的动态代理和CGLIB动态代理为数据库增加了日志记录功能。然而,生成的动态代理类到底是个什么样子呢?本章我们就一起来揭开它...

空空如也

1 2 3 4 5 ... 20
收藏数 85,332
精华内容 34,132
关键字:

代理模式