精华内容
下载资源
问答
  • 本文来自csdn,本文全面讲解Android开发中最常用的设计模式-代理模式中的动态代理模式.代理模式中的静态代理模式存在一些特点:1个静态代理只服务1种类型的目标对象若要服务多类型的目标对象,则需要为每种目标对象...
  • 秒懂Java代理与动态代理模式

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

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

    设计模式汇总篇,一定要收藏:

    永不磨灭的设计模式(有这一篇真够了,拒绝标题党)

    概述

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

    类型

    结构型(structural)

    难度

    3颗星

    概念

    什么是代理模式

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

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

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

    解决什么问题

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

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

    什么是静态代理

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

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

    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

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

    GitHub源码地址design-patterns

    展开全文
  • 动态代理模式

    千次阅读 2019-08-23 01:10:57
    动态代理模式Jdk动态代理Cglib动态代理 动态代理就是在实现阶段不用关心代理谁,而在运行期才指定代理哪一个对象 Jdk动态代理 游戏大家可能都玩过,但是一些游戏升级就很难或者说是很耗费时间,所以就有好多人去找...


    动态代理就是在实现阶段不用关心代理谁,而在运行期才指定代理哪一个对象

    Jdk动态代理

    游戏大家可能都玩过,但是一些游戏升级就很难或者说是很耗费时间,所以就有好多人去找游戏代练进行升级。

    public interface IGamePlayer {
        void play();
    }
    
    public class GamePlayer implements IGamePlayer {
        @Override
        public void play() {
            System.out.println("玩游戏,升级...");
        }
    }
    

    好了我们已经定义好了自己玩游戏的接口和类了,现在我们再去找个代理帮我们玩

    public class JdkProxy implements InvocationHandler {
    
        //目标对象
        private Object target;
    
        /**
         * 建立代理对象和真实对象的代理关系,并返回代理对象
         * @param object    真实对象
         * @return      代理对象
         *
         * 其中newProxyInstance方法包含了3个参数:
         *  (1)第一个是类加载器,采用了target本身的类加载器
         *  (2)第二个是把生成的动态代理对象挂在哪些接口下,这个就是挂在target实现的接口下
         *  (3)第三个定义实现方法逻辑的代理类,this表示当前对象
         */
        public Object getProxy(Object object){
            this.target = object;
            Object proxy = Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
            return proxy;
        }
    
        /**
         * @param proxy     代理对象
         * @param method    当前调度方法
         * @param args      当前方法参数
         * @return          代理结果返回
         * @throws Throwable        异常
         *
         * invoke方法可以实现代理逻辑,invoke方法3个参数含义如下:
         * (1)proxy:代理对象,就是bind生成的对象
         * (2)method:当前调度的方法。
         * (3)args:调度方法的参数
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            return method.invoke(target,args);
        }
    }
    

    我们可以看到上述动态代理类,在代码中并不用向我们的静态代理一样,需要把GamePlayer类指定进行,我们在运行过程中,确定了要代理GamePlayer类时,再指定就可以啦

    下面我们就在场景类中测试一下

    public class Client {
        public static void main(String[] args) {
            IGamePlayer gamePlayer = new GamePlayer();
            JdkProxy jdkProxy = new JdkProxy();
            //获取代理对象,因为挂在接口IGamePlayer下,所以声明代理对象IGamePlayer
            IGamePlayer proxy = (IGamePlayer) jdkProxy.getProxy(gamePlayer);
            proxy.play();
        }
    }
    

    打印结果

    玩游戏,升级...
    

    那动态代理有什么好处了,我们可以看看我们之前 静态代理模式 中只指定代理了一个接口,万一我们想要代理两个怎么办?
    要么我们写两个类分别继承两个接口

    public interface class1 implements interface1{
    }
    public interface class2 implements interface2{
    }
    

    目标对象这样,那么我们的代理对象肯定要要分为两个类,分别代理这两个对象,这样类就太多了,那么我们就只能使用继承多个接口的方法

    public interface class1 implements interface1, interface1{
    	@Override
    	public void method1(){
    	}
        @Override
    	public void method2(){
    	}
    }
    

    这样但是万一我们在重写接口方法 (method1, method2) 中invoke目标方法时在调用前、调用后分别进行一些处理,那就会造成代码冗余。

    那我们的动态代理可以解决吗?
    比如说游戏代练除了帮人代练游戏,还帮人代卖的游戏账号

    public interface ISellAccount {
        void sell();
    }
    

    那我们的游戏者再多实现一个ISellAction的接口

    public class GamePlayer implements IGamePlayer, ISellAccount {
        @Override
        public void play() {
            System.out.println("玩游戏,升级...");
        }
    
        @Override
        public void sell() {
            System.out.println("出售游戏账号...");
        }
    }
    

    至于我们的动态代理类都不需要变动,只要在场景类中指定我们想要代理的接口就好

    public class Client {
        public static void main(String[] args) {
            IGamePlayer gamePlayer = new GamePlayer();
            JdkProxy jdkProxy = new JdkProxy();
            //如想要出售游戏账号
            ISellAccount proxy1 = (ISellAccount) jdkProxy.getProxy(gamePlayer);
            proxy1.sell();
            //如想要找代练升级
            IGamePlayer proxy2 = (IGamePlayer) jdkProxy.getProxy(gamePlayer);
            proxy2.play();;
        }
    }
    

    如上我们也应该清楚了,在我们的Jdk动态代理中,被代理的目标对象必须要有接口,因为我们Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)的第二个参数需要传入目标对象实现的接口,用于我们将生成的代理对象挂在哪一个接口之下(可多个接口,使用方法如上)。

    Cglib动态代理

    jdk动态代理我们发现被代理的目标对象必须要有接口,但是有的类没有接口怎么办呢,就不能使用代理了么,可以,那就需要使用到我们的Cglib动态代理啦

    要是我们不是在Spring环境下,使用Cglib需要引入相应的jar包,依赖如下,也可以下载相应的 .jar文件导入项目中

    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>3.2.12</version>
    </dependency>
    

    cglib动态代理类如下

    public class CglibProxy implements MethodInterceptor {
    
        public Object getProxy(Class clazz){
            //CGLIB enhancer增强类对象
            Enhancer enhancer = new Enhancer();
            //设置增强类型(父类)
            enhancer.setSuperclass(clazz);
            //定义代理逻辑对象为当前对象,要求当前对象实现MethodInterceptor方法
            enhancer.setCallback(this);
            //生成并返回代理对象
            return enhancer.create();
        }
    
        @Override
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            //proxy是代理后的子类
            return methodProxy.invokeSuper(proxy, args);
        }
    }
    

    在Client类中,用cglib动态代理为GamePlayer生成一个代理对象,并调用其方法

    public class Client {
        public static void main(String[] args) {
            CglibProxy cglibProxy = new CglibProxy();
            GamePlayer proxy = (GamePlayer) cglibProxy.getProxy(GamePlayer.class);
            proxy.play();
        }
    }
    
    玩游戏,升级...
    

    我们在上述过程中就会发现,cglib动态代理就没有像jdk动态代理上代理的目标对象有着接口的要求。

    展开全文
  • 代理模式使用场景 代理模式的定义:什么是代理模式呢?代理模式是常用的Java设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息...

    代理模式使用场景

    代理模式的定义:什么是代理模式呢?代理模式是常用的Java设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类和委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不是真正实现服务,而是通过调用委托类对象的相关的方法来提供特定的服务。

    举个例子来说明:假如说我现在想买一辆二手车,虽然我可以自己去找车源,做质量检测等一系列的车辆过户流程,但是这确实太浪费我得时间和精力了。我只是想买一辆车而已为什么我还要额外做这么多事呢?于是我就通过中介公司来买车,他们来给我找车源,帮我办理车辆过户流程,我只是负责选择自己喜欢的车,然后付钱就可以了。

    上述例子中:委托类就是我,

    委托类的方法:选车+付钱

    代理类:过户,质量检测,或许还有一些杂七杂八的事情,每个委托人也许杂七杂八的事情还不同,都通过代理类来处理,而委托类只需完成核心的业务,选车付钱就行了。

    用图表示如下(网图):

    https://images2017.cnblogs.com/blog/1071931/201801/1071931-20180108134122472-1822105846.png

    为什么要用代理模式?

    中介隔离作用:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。

    开闭原则,增加功能:代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的委托类。

     

    静态代理模式

    由程序员或特定工具自动生成的源代码,再对其编译,在程序运行之前,代理的类编译生成的.class文件就已经存在了。

     

    直接上代码:

    接口:

    public interface A {
    
        void buyCar();
    
        void sallCar(String string);
    
    }

     

    实现类(委托类):

    public class AImpl implements A {
    
        public void buyCar() {
    
            System.out.println("我要买车");
    
        }
    
        public void sallCar(String s){
    
            System.out.println("sall car" + s);
    
        }
    
    }

     

    代理类:

    public class StaticStateProxy implements A {
    
        private A a;
    
        public StaticStateProxy(A a){
            this.a = a;
        }
    
    public void buyCar(){
    
           //do something
            a.buyCar();
            //do something
    
    }
    
        public void sallCar(String string){
    
            a.sallCar(string);
    
        }
    
    }
    
    

    测试:

    public class StaticStateProxyTest{
    
    
    
        public static void main(String[] args) {
    
            A a = new AImpl();
    
            a.buyCar();
    
            StaticStateProxy buyHouseProxy = new StaticStateProxy(a);
    
            buyHouseProxy.buyCar();
    
        }
    
    }

    静态代理总结:

    1、代理类和实现类(委托类),继承同一个接口类A。

    2、代理类中传入接口A的实现类,通过重写接口A的方法,在重写方式时,直接调用传入A实现类的方法,并且在调用前后可以做一些其他操作,结合本章开始的例子,这里就是通过代理类,来实现委托类方法的同事,做一些其他操作。

    优缺点:

    优点:可以做到在符合开闭原则的情况下对目标对象进行功能扩展,调用比较简单。

    缺点:我们得为每一个服务都得创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改。 

     

    JDK动态代理模式

    动态代理是在程序运行时通过反射机制动态创建的,在动态代理中我们不再需要再手动的创建代理类,我们只需要编写一个动态处理器就可以了。真正的代理对象由JDK再运行时为我们动态的来创建。

    上代码:

    接口:

    public interface A {
    
        void buyCar();
    
        void sallCar(String string);
    
    }

     

    实现类(委托类):

    public class AImpl implements A {
    
        public void buyCar() {
    
            System.out.println("我要买车");
    
        }
    
        public void sallCar(String s){
    
            System.out.println("sall car" + s);
    
        }
    
    }

    代理类:

    import java.lang.reflect.InvocationHandler;
    
    import java.lang.reflect.Method;
    
    
    
    public class DynamicProxyHandler implements InvocationHandler {
    
    
        private Object object;
    
        public DynamicProxyHandler(final Object object) {
    
            this.object = object;
    
        }
    
    
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
            System.out.println("买车前凑钱");
    
            Object result = method.invoke(object, args);
    
            System.out.println("买车后飙车");
    
            return result;
    
        }
    
    }

    测试:

    import java.lang.reflect.Proxy;
    
    
    
    public class DynamicProxyTest {
    
        public static void main(String[] args) {
    
    
    
            A a = new AImpl();
    
    
    
            A proxyA = (A) Proxy.newProxyInstance(A.class.getClassLoader(), new
    
                    Class[]{A.class}, new DynamicProxyHandler(a));
    
    
    
            proxyA.buyCar();
    
            proxyA.sallCar("BMW");
    
        }
    
    }

    动态代理总结:

    动态代理的接口和实现类和静态代理一样,主要是看代理类的实现:

    DynamicProxyHandler实现了InvocationHandler接口。

    每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法

    换句话说,我们一般调用方法都是采用a.method这种方式,代码会直接走到method方法中,而使用了动态代理类,我们需要通过InvocationHandler中的invoke来调用该方法,这样做有什么好处呢,最浅显的理解,就是在invoke中,除了通过method.invoke(object, args)来调用该方法以外,还可以做其他操作,如以上代码所示。

    在写好代理类后,需要创建一个代理类的实例,来调用方法,创建方式为:

    Proxy.newProxyInstance

    注意Proxy.newProxyInstance()方法接受三个参数:

    ClassLoader loader:指定当前目标对象使用的类加载器,也就是委托类,获取加载器的方法是固定的

    Class<?>[] interfaces:指定目标对象实现的接口的类型,也就是委托类的接口,使用泛型方式确认类型

    InvocationHandler:指定动态处理器,也就是制定代理类,执行目标对象的方法时,会触发事件处理器的方法。

    动态代理和静态代理的比较:

     动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样,重实现接口的每个方法,每一个方法都需要进行中转。而且动态代理的应用使我们的类职责更加单一,复用性更强;

    但是:动态代理只能代理实现了接口的类,没有实现接口的类不能实现JDK动态代理。这时我们就需要用到Cglib代理。

     

    Cglib代理模式

    JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要CGLib了。CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。但因为采用的是继承,所以不能对final修饰的类进行代理。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。 Cglib不是java自带的API,我们要使用cglib代理必须引入 cglib的jar包。

    上代码,借用上述例子实现类:

    public class AImpl implements A {
    
        public void buyCar() {
    
            System.out.println("我要买车");
    
        }
    
        public void sallCar(String s){
    
            System.out.println("sall car" + s);
    
        }
    
        public String aa(){
    
            return "aa";
    
        }
    
    }

     

    代理类:

    public class CglibMethodInterceptor implements MethodInterceptor {
    
    
    
        public Object intercept(Object object , Method method , Object[] args, MethodProxy methodProxy) throws Throwable {
    
    
    
            System.out.println("Before");
    
            Object result = methodProxy.invokeSuper(object,args);
    
            System.out.println("After");
    
            return result;
    
        }
    
    }
    
    

    测试:

    public class CglibProxyTest {
    
        public static void main(String[] args) {
    
            Enhancer enhancer = new Enhancer();
    
            enhancer.setSuperclass(AImpl.class);
    
            enhancer.setCallback(new CglibMethodInterceptor());
    
            AImpl aImpl = (AImpl) enhancer.create();
    
            aImpl.buyCar();
    
            aImpl.sallCar("dd");
    
        }
    
    }

    代理类定义了一个拦截器,在调用目标方法之前,cglib回调MethodInterceptor接口方法拦截,来实现自己的业务逻辑,类似于JDK中的InvocationHandler接口。也就是通过intercept 调用methodProxy.invokeSuper来调用委托类的方法,而在intercept中可以做其他工作。

    public Object intercept(Object object , Method method , Object[] args, MethodProxy methodProxy)

    object:为cglib动态生成的代理实例

    method:为上文中实体类所调用的被代理的方法调用

    args:为method参数数值列表

    methodProxy:为生成代理类对方法的代理引用

    返回:从代理实例方法调用返回的值

    其中,methodProxy.invokeSuper(object,args):

    调用代理类实例上的proxy方法的父类方法

    (这里有点拗口,简单一点就是,调用代理类实例的父类方法,为什么是父类方法,因为在创建代理类实例时,需要将代理类设置为委托类的子类,下面会有提到)

    在写好代理类后,需要创建一个代理类的实例,来调用方法。

    代理类对象是由Enhancer类创建的。Enhancer是CGLIB的字节码增强器,可以很方便的对类进行拓展。

    创建代理对象的几个步骤:

         Enhancer enhancer = new Enhancer();   1

            enhancer.setSuperclass(AImpl.class);  2

            enhancer.setCallback(new CglibMethodInterceptor());  3

            AImpl aImpl = (AImpl) enhancer.create();      4

            aImpl.buyCar();

            aImpl.sallCar("dd");

    1. 创建Enhancer实例。
    2. 继承被委托类,也就是说enhance对应的类为Alpml的子类。
    3. enhancer.setCallback()这个方法,我们需要传入CglibMethodInterceptor的实例作为回调的对象,并且把它放入到一个Callback类型的数组里面。然后去判断这个数组是否合法。
    4. 最后一步enhancer.create()返回的是一个增强的目标类的实例,此时的AImpl对象已经不是以前那个AImpl类的, 而是一个增强后的AImpl类的实例了,每个方法都有代理类中的增加语句。

     

    至此,CGlib就告一段落,等后续有时间,对源码解析一番就更好了。

     

    三种代理方式的对比

    网上有一段CGLIB和JDK动态带路使用场景上的对比,就借用一下啦:

    CGLIB创建的动态代理对象比JDK创建的动态代理对象的性能更高,但是CGLIB创建代理对象时所花费的时间却比JDK多得多。所以对于单例的对象,因为无需频繁创建对象,用CGLIB合适,反之使用JDK方式要更为合适一些。同时由于CGLib由于是采用动态创建子类的方法,对于final修饰的方法无法进行代理。

     

    代理方式

    实现

    优点

    缺点

    特点

    JDK静态代理

    代理类与委托类实现同一接口,并且在代理类中需要硬编码接口

    实现简单,容易理解

    代理类需要硬编码接口,在实际应用中可能会导致重复编码,浪费存储空间并且效率很低

    好像没啥特点

    JDK动态代理

    代理类与委托类实现同一接口,主要是通过代理类实现InvocationHandler并重写invoke方法来进行动态代理的,在invoke方法中将对方法进行增强处理

    不需要硬编码接口,代码复用率高

    只能够代理实现了接口的委托类

    底层使用反射机制进行方法的调用

    CGLIB动态代理

    代理类将委托类作为自己的父类并为其中的非final委托方法创建两个方法,一个是与委托方法签名相同的方法,它在方法中会通过super调用委托方法;另一个是代理类独有的方法。在代理方法中,它会判断是否存在实现了MethodInterceptor接口的对象,若存在则将调用intercept方法对委托方法进行代理

    可以在运行时对类或者是接口进行增强操作,且委托类无需实现接口

    不能对final类以及final方法进行代理

    底层将方法全部存入一个数组中,通过数组索引直接进行方法调用

     

     

    展开全文
  • java中的装饰模式及动态代理模式示例源码,并且手写数据库连接池,以及展示动态代理模式在连接池中的使用
  • JAVA动态代理模式.pdf

    2021-10-03 23:52:05
    JAVA动态代理模式.pdf
  • 代理模式与动态代理模式

    千次阅读 多人点赞 2015-03-19 09:35:14
    1、代理模式 所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用。 代理模式给某...

    原文地址:点击打开链接

    1、代理模式

    所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用。
    代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。

    生活中的例子:过年加班比较忙,没空去买火车票,这时可以打个电话到附近的票务中心,叫他们帮你买张回家的火车票,当然这会附加额外的劳务费。但要清楚票务中心自己并不卖票,只有火车站才真正卖票,票务中心卖给你的票其实是通过火车站实现的。这点很重要!

    上面这个例子,你就是“客户”,票务中心就是“代理角色”,火车站是“真实角色”,卖票称为“抽象角色”!


    代理模式JAVA代码示例:
     1 // 抽象角色:抽象类或接口
     2 interface  Business
     3 {
     4    void doAction();
     5}

     6 // 真实角色:真正实现了业务逻辑接口
     7 class  BusinessImpl  implements  Business
     8 {
     9    public void doAction()
    10    {
    11        System.out.println("真实角色中的方法被执行!");
    12    }

    13}

    14 // 代理角色:自己并未实现业务逻辑接口,而是调用真实角色来实现
    15 class  BusinessImplProxy  implements  Business
    16 {
    17    private BusinessImpl bi;
    18    public void doAction()
    19    {
    20        if (bi==null)
    21        {
    22            bi = new BusinessImpl();
    23        }

    24        doBefore();
    25        bi.doAction();
    26        doAfter();
    27    }

    28    public void doBefore()
    29    {
    30        System.out.println("前置处理!");
    31    }

    32    public void doAfter()
    33    {
    34        System.out.println("后置处理!");
    35    }

    36}

    37 // 测试类
    38 class  Test
    39 {
    40    public static void main(String[] args)
    41    {
    42        //引用变量定义为抽象角色类型
    43        Business bi = new BusinessImplProxy();
    44        bi.doAction();
    45    }

    46}

    47

    代理模式允许使用抽象类或接口作为“抽象角色”,每个“代理角色”代理了一个“真实角色”,如果要代理的“真实角色”比较多,这势必造成大量的“代理角色”造成代码的急剧膨胀,其实其内部结构都是类似的,要是在运行时能动态生成“代理角色”就好了。

    2、JAVA中的动态代理模式

    从JDK1.3开始,java中引入了动态代理机制。相关的接口或类有如下两个:InvocationHandler和Proxy,都位于java.lang.reflect包下
    InvocationHandler接口只定义了一个抽象方法:
            Object  invoke (Object proxy, Method method, Object[] args) 
    Proxy类中主要的2个静态方法:
            Class<?>  getProxyClass (ClassLoader loader, Class<?>... interfaces) 
            Object  newProxyInstance (ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
            getProxyClass返回一个动态创建的代理类(Class),newProxyInstance则返回改代理类的实例(Object)。

    所以,借助于JVM的支持,可以在运行时动态生成代理类(“代理角色”),我们就可以解决上述代理模式中代码膨胀的问题,使用了动态代理后,“代理角色”将不用手动生成,而由JVM在运行时,通过指定类加载器、接口数组、调用处理程序这3个参数来动态生成。

    动态代理模式JAVA代码示例:
     1 import  java.lang.reflect.InvocationHandler;
     2 import  java.lang.reflect.Proxy;
     3 import  java.lang.reflect.Method;
     4 // 抽象角色:java动态代理的实现目前只支持接口,不支持抽象类
     5 interface  BusinessFoo
     6 {
     7    void foo();
     8}

     9 interface  BusinessBar
    10 {
    11    String bar(String message);
    12}

    13 // 真实角色:真正实现业务逻辑方法
    14 class  BusinessFooImpl  implements  BusinessFoo
    15 {
    16    public void foo()
    17    {
    18        System.out.println("BusinessFooImpl.foo()");
    19    }

    20}

    21 class  BusinessBarImpl  implements  BusinessBar
    22 {
    23    public String bar(String message)
    24    {
    25        System.out.println("BusinessBarImpl.bar()");
    26        return message;
    27    }

    28}

    29 // 动态角色:动态生成代理类
    30 class  BusinessImplProxy  implements  InvocationHandler
    31 {
    32    private Object obj;
    33    BusinessImplProxy() {
    34    }

    35    BusinessImplProxy(Object obj) {
    36        this.obj = obj;
    37    }

    38    public Object invoke(Object proxy,Method method,Object[] args) throws Throwable
    39    {
    40        Object result = null;
    41        doBefore();
    42        result = method.invoke(obj,args);
    43        doAfter();
    44        return result;
    45    }

    46    public void doBefore(){
    47        System.out.println("do something before Business Logic");
    48    }

    49    public void doAfter(){
    50        System.out.println("do something after Business Logic");
    51    }

    52    public static Object factory(Object obj)
    53    {
    54        Class cls = obj.getClass();
    55        return Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),new BusinessImplProxy(obj));
    56    }

    57}

    58 // 测试类
    59 public   class  DynamicProxy
    60 {    
    61    public static void main(String[] args) throws Throwable
    62    {
    63        BusinessFooImpl bfoo = new BusinessFooImpl();
    64        BusinessFoo bf = (BusinessFoo)BusinessImplProxy.factory(bfoo);
    65        bf.foo();
    66        System.out.println();
    67        
    68        BusinessBarImpl bbar = new BusinessBarImpl();
    69        BusinessBar bb = (BusinessBar)BusinessImplProxy.factory(bbar);
    70        String message = bb.bar("Hello,World");
    71        System.out.println(message);
    72    }

    73}

    程序流程说明:
           new BusinessFooImpl();创建一个“真实角色”,传递给工厂方法BusinessImplProxy.factory(),进而初始化“调用处理器”——即实现InvocationHandler的类。并返回一个动态创建的代理类实例,由于“代理角色”也必然实现了“抽象角色”提供的业务逻辑方法,故可向下转型为BusinessBar,并赋值给指向BusinessBar类型的引用bb。
           newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法由程序员来指定参数动态返回需要的代理类,而invoke(Object proxy, Method method, Object[] args) 方法则是由JVM在运行时动态调用的。当执行“bb.bar("Hello,World");”方法时,JVM动态指派“调用处理器”,向外层invoke传递参数,并调用method.invoke(obj,args)真正执行!

    BusinessImplProxy.Factory静态方法用来动态生成代理类(“代理角色”),在运行时根据不同的业务逻辑接口BusinessFoo和BusinessBar,在运行时分别动态生成了代理角色。“抽象角色”、“代理角色”以及调用处理器(实现InvocationHandler接口的类)这三者都可以改变,所以说JAVA的动态代理十分强大。


    展开全文
  • 基于java的jdk动态代理, 比较了静态代理与动态代理的区别,以及动态代理的底层实现,反编译class文件 jdk动态代理和cglib的区别
  • Java设计模式模式---动态代理模式

    千次阅读 2018-08-15 21:48:15
    代理模式 代理模式的意图是通过一个接口或者占位符来控制对该对象的访问 代理对象通常拥有一个和真实对象相同的接口,通过控制访问将请求合理的转发给底层真实的对象 动态代理(需要代理的类实现了接口) 通过...
  • 文章目录1 引子2 业务场景介绍3 静态代理模式4 装饰器模式5 动态代理模式 1 引子 看过上篇文章《【Mybatis源码探索】 — Mybatis查询过程核心源码解读 — 先聊聊selectOne方法》对Executor和StatementHandler的...
  • 动态代理模式实现界面跳转传值,里面包含了静态代理的使用
  • AOP的意思就是面向切面编程。本文主要是通过梳理JDK中自带的反射机制,实现 AOP动态代理模式,这也是Spring AOP 的实现原理
  • 而且要理解动态代理,需要对于java反射的概念有所了解,不了解的同学可以先去了解下反射的基础概念。什么是代理首先 代理,从汉语去理解的话,就是我本来自己一个人能做的事,我不亲自去做,让另一个人帮我做。这个...
  • 跟踪消费方创建代理对象的过程在ReferenceConfig中实现 //在init方法中创建代理对象,init在工厂方法FactoryBean的getObject()中调用 ref = createProxy(map); /** * 在createProxy(Map map) 方法最后一行根据...
  • Java 反射6-动态代理模式

    千次阅读 2018-05-22 16:11:15
      动态代理模式的核心特点:一个代理类可以代理所有需要被代理的接口的子类对象,如下所示:   N个接口, N+1个类, 其中 N 个真是业务类,1个代理类(在运行时动态获取当前要代理的接口)。   所以要使用...
  • 动态代理模式 适配器模式 实现,都可以运行,有一部分注解
  • 轻松学,Java 中的代理模式动态代理

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

    千次阅读 2017-09-10 15:47:17
    1、什么叫代理模式: &amp;amp;amp;amp;nbsp;&amp;amp;amp;amp;nbsp;&amp;amp;amp;amp;nbsp;&amp;amp;amp;amp;nbsp;&amp;amp;amp;amp;nbsp;&amp;amp;amp;amp;nbsp;&amp;amp;amp;amp;...
  • 狂神说Spring06:静态/动态代理模式

    千次阅读 多人点赞 2020-04-21 10:22:56
    狂神说Spring系列连载课程,通俗易懂,基于Spring最新版本,欢迎各位狂粉转发关注学习。禁止随意转载,转载记住贴出B站视频链接及公众号链接!代理模式为什么要学习代理模式,因为AOP...
  • 【设计模式之代理模式】—静态代理和动态代理

    千次阅读 热门讨论 2018-07-31 18:01:31
    前言 ...今天咱们来说下代理模式。 正文 代理模式 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;为另一个对象提供一个替身或占位符以控制这个对象的访问。 &
  • 工厂模式 代码实现: 步骤一:创建一个接口 Car.java package FactoryMode; public interface Car { public void run(); } 步骤二:创建实现类 BaoMaCar.java package FactoryMode; public class BaoMaCar ...
  • 自己编写的设计模式示例,绝对不含伪代码,示例简单易懂 适合初学者学习使用
  • - 代理模式 - 概念: (1). 真实对象:被代理的对象 (2).... (3). 代理模式:代理对象代理真实对象,达到增强真实对象功能的目的 - 实现方式: (1). 静态代理:有一个类文件... 动态代理:在内存中形成代理类
  • 为其他对象提供一种代理以控制这个对象的访问,在某些情况下一个对象不能直接访问那个对象时,代理就起到了客户端和被代理对象(委托类)中介作用。 代理类和委托类都有同样接口。 好处:可以不用动原来类的逻辑,...
  • Java高级特性反射与动态代理模式

    千次阅读 多人点赞 2020-10-06 11:36:46
    动态代理模式,也是Java中常见的一种设计模式,其中动态代理模式,也是用到了反射,所以我们反射和动态代理一起学一学,最后我们分析JDK的Proxy是怎么为我们生成代理类的!最后别忘了一键三连哦
  • 深入理解代理模式:静态代理与JDK动态代理

    万次阅读 多人点赞 2018-03-01 00:22:11
     代理模式为其他对象提供了一种代理以控制对这个对象的访问,具体实现包括两大类:静态代理和动态代理。Java动态代理机制的出现使得Java开发人员只需要简单地指定一组接口及委托类对象便能动态地获得代理类,并且其...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 243,574
精华内容 97,429
关键字:

动态代理模式