当前位置:首页 > CN2资讯 > 正文内容

代理模式代理模式缺点

1天前CN2资讯

定义:为另一个对象提供一个替身或占位符以控制这个对象的访问。

 ​

 

1、JDK自带的动态代理(代理必须实现接口)

理解

动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。


我们知道,所谓代理,就是需要代理类和被代理类有相同的对外接口或者说成服务,所以代理类一般都必须实现了所有被代理类已实现的接口,因为接口就是制定了一系列对外服务的标准。


 


正因为动态代理有这样灵活的特性,所以我们在设计动态代理类(DynamicProxy)时不用显式地让它实现与真实主题类(RealSubject)相同的接口(interface),而是把这种实现推迟到运行时。


 


为了能让DynamicProxy类能够在运行时才去实现RealSubject类已实现的一系列接口并执行接口中相关的方法操作,需要让DynamicProxy类实现JDK自带的java.lang.reflect.InvocationHandler接口,该接口中的invoke()方法能够让DynamicProxy实例在运行时调用被代理类的“对外服务”,即调用被代理类需要对外实现的所有接口中的方法,也就是完成对真实方法的调用,Java帮助文档中称这些真实方法为处理程序。


 


按照上面所述,我们肯定必须先把被代理类RealSubject已实现的所有interface都加载到JVM中,不然JVM怎么能够找到这些方法呢?明白了这个道理,那么我们就可以创建一个被代理类的实例,获得该实例的类加载器ClassLoader。


 


所谓的类加载器ClassLoader,就是具有某个类的类定义,即类的内部相关结构(包括继承树、方法区等等)。


 


更重要的是,动态代理模式可以使得我们在不改变原来已有的代码结构的情况下,对原来的“真实方法”进行扩展、增强其功能,并且可以达到控制被代理对象的行为的目的。请详看下面代码中的DynamicProxy类,其中必须实现的invoke()方法在调用被代理类的真实方法的前后都可进行一定的特殊操作。这是动态代理最明显的优点。


 


虽然都是根据自己看了书之后的理解说了这么多,不知道能不能让人明白,这里先给出动态代理的类图吧,如下:


​​​​


具体代码实现如下:

  • import java.lang.reflect.InvocationHandler;  
  • import java.lang.reflect.Method;  
  • import java.lang.reflect.Proxy;  
  •  
  • //抽象主题类,这里不能用abstract抽象类,一定要是interface  
  • interface AbstractSubject {  
  •     public abstract void request();  
  • }  
  •  
  • // 真实主题类,即被代理类  
  • class RealSubject implements AbstractSubject {  
  •     public void request() {  
  •         System.out.println("RealSubject's request() ...");  
  •     }  
  • }  
  •  
  • // 动态代理类,实现InvocationHandler接口  
  • class DynamicProxy implements InvocationHandler {  
  •  
  •     // 被代理类的实例  
  •     Object obj = null;  
  •  
  •     // 将被代理者的实例传进动态代理类的构造函数中  
  •     public DynamicProxy(Object obj) {  
  •         this.obj = obj;  
  •     }  
  •  
  •     /**  
  •      * 覆盖InvocationHandler接口中的invoke()方法  
  •      *   
  •      * 更重要的是,动态代理模式可以使得我们在不改变原来已有的代码结构  
  •      * 的情况下,对原来的“真实方法”进行扩展、增强其功能,并且可以达到  
  •      * 控制被代理对象的行为,下面的before、after就是我们可以进行特殊  
  •      * 代码切入的扩展点了。  
  •      */ 
  •     public Object invoke(Object proxy, Method method, Object[] args)  
  •             throws Throwable {  
  •         /*  
  •          * before :doSomething();  
  •          */ 
  •         Object result = method.invoke(this.obj, args);  
  •           
  •         /*  
  •          * after : doSomething();  
  •          */ 
  •         return result;  
  •     }  
  • }  
  •  
  • // 测试类  
  • public class Client {  
  •     public static void main(String[] args) {  
  •  
  •         // 被代理类的实例  
  •         AbstractSubject realSubject = new RealSubject();  
  •  
  •         // 获得被代理类的类加载器,使得JVM能够加载并找到被代理类的内部结构,以及已实现的interface  
  •         ClassLoader loader = realSubject.getClass().getClassLoader();  
  •  
  •         // 获得被代理类已实现的所有接口interface,使得动态代理类的实例  
  •         Class<?>[] interfaces = realSubject.getClass().getInterfaces();  
  •  
  •         // 用被代理类的实例创建动态代理类的实例,用于真正调用处理程序  
  •         InvocationHandler handler = new DynamicProxy(realSubject);  
  •  
  •         /*  
  •          * loader : 被代理类的类加载器  
  •          * interfaces :被代理类已实现的所有接口,而这些是动态代理类要实现的接口列表  
  •          * handler : 用被代理类的实例创建动态代理类的实例,用于真正调用处理程序  
  •          *   
  •          * return :返回实现了被代理类所实现的所有接口的Object对象,即动态代理,需要强制转型  
  •          */ 
  •         //获得代理的实例  
  •         AbstractSubject proxy = (AbstractSubject) Proxy.newProxyInstance(  
  •                 loader, interfaces, handler);  
  •  
  •         proxy.request();  
  •         //打印出该代理实例的名称  
  •         System.out.println(proxy.getClass().getName());  
  •     }  
  •  

     


    测试结果:

    RealSubject's request() ...


    DesignPattern.proxy.dynamicProxy.$Proxy0 


    为什么JDK动态代理只能代理实现了接口的类



    可以打印出代理类的字节码,从该类的声明中可以看到,继承了Proxy类,并实现了目标接口。验证了上文中的论点——所有生成的动态代理类都是Proxy类的子类。同时也解释了为什么JDK动态代理只能代理实现了接口的类——Java不支持多继承,代理类已经继承了Proxy类,无法再继承其它类。


     

     

    2.cglib(是直接修改字节码,可以用继承实现代理)

    JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

     

    public interface BookFacade {  

        public void addBook();  

    }  

     

    /** 

     * 这个是没有实现接口的实现类 

     *  

     * @author student 

     *  

     */  

    public class BookFacadeImpl1 {  

        public void addBook() {  

            System.out.println("增加图书的普通方法...");  

        }  

    }  

     

    import java.lang.reflect.Method;  


    import net.sf.cglib.proxy.Enhancer;  

    import net.sf.cglib.proxy.MethodInterceptor;  

    import net.sf.cglib.proxy.MethodProxy;  


    /** 

     * 使用cglib动态代理 

     *  

     * @author student 

     *  

     */  

    public class BookFacadeCglib implements MethodInterceptor {  

        private Object target;  


        /** 

         * 创建代理对象 

         *  

         * @param target 

         * @return 

         */  

        public Object getInstance(Object target) {  

            this.target = target;  

            Enhancer enhancer = new Enhancer();  

            enhancer.setSuperclass(this.target.getClass());  

            // 回调方法  

            enhancer.setCallback(this);  

            // 创建代理对象  

            return enhancer.create();  

        }  


        @Override  

        // 回调方法  

        public Object intercept(Object obj, Method method, Object[] args,  

                MethodProxy proxy) throws Throwable {  

            System.out.println("事物开始");  

            proxy.invokeSuper(obj, args);  

            System.out.println("事物结束");  

            return null;  

        }  

    }  

     

    import net.battier.dao.impl.BookFacadeImpl1;  

    import net.battier.proxy.BookFacadeCglib;  


    public class TestCglib {  


        public static void main(String[] args) {  

            BookFacadeCglib cglib=new BookFacadeCglib();  

            BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());  

            bookCglib.addBook();  

        }  

    }  

      你可能想看:

      扫描二维码推送至手机访问。

      版权声明:本文由皇冠云发布,如需转载请注明出处。

      本文链接:https://www.idchg.com/info/24075.html

      标签: 代理模式
      分享给朋友:

      “代理模式代理模式缺点” 的相关文章

      CloudCone VPS评测:高性能与灵活计费方案的完美结合

      在谈论CloudCone VPS之前,让我给你介绍一下这家服务商。CloudCone成立于2017年,起源于美国,主要是在洛杉矶的MultaCom机房提供云主机和VPS服务。自创立以来,CloudCone逐步发展壮大,不断优化和提升其服务质量,为用户提供便捷的云计算解决方案。可以说,CloudCon...

      UCloud优:云计算服务平台的领先者与优势分析

      UCloud优的基本介绍 谈到UCloud,首先让我想起它成立的背景以及它是如何从一颗种子成长为今天的云计算巨头。UCloud,或者说优刻得科技股份有限公司,于当时顺应了数字化转型的浪潮。这是一个中立、安全的云计算服务平台,专注于为各行各业提供云服务。它的创立背景与各种市场需求紧密相连,尤其是企业对...

      eno VPS:掌握网络接口命名规则与性能优化技巧

      在了解eno VPS之前,我们先来看看什么是eno命名规则。ena作为一种网络接口命名方式,通过特定的规则来表示Linux系统中的网络设备。这种规则帮助用户更容易地识别和管理各种网络接口。具体来说,eno采用的是eno[n|d]的格式,主要用于板载设备。而对于热插拔设备,则使用ens[f][n|d]...

      选择合适的Linux SSH工具来提升远程管理效率

      在数字化时代,远程连接与管理变得尤为重要。SSH(Secure Shell)是一种网络协议,用于通过不安全的网络安全地访问计算机。SSH技术保障了数据的隐私和完整性,并通过加密通道进行通信。当我第一次接触SSH时,它对于在不同计算机之间安全地进行操作以及文件传输是多么重要,印象深刻。 SSH不仅仅是...

      如何选择合适的IPv6 VPS服务商与其优势分析

      当我第一次接触到IPv6 VPS时,我意识到这一概念不仅为技术界带来了全新的视野,也为我们解决互联网地址匮乏的问题提供了有效的方案。IPv6,全称为互联网协议第六版,设计的目的是为了替代现有的IPv4协议,以应对未来互联网规模的增长。IPv6不仅增加了可用的地址数量,更在安全性和效率上进行了提升,是...

      如何使用Windows网络诊断工具查找服务器地址和解决网络问题

      在当今这个网络无处不在的时代,能够快速诊断网络问题已变得尤为重要。作为Windows用户,我们的设备中自带了一个非常实用的工具——Windows网络诊断工具。说到这个工具,许多人可能不太了解它的具体功能和用途。 Windows网络诊断工具是一个集成在Windows操作系统中的应用,专门用于帮助用户识...