设计模式之代理模式(静态代理和动态代理)

2019-03-12 23:17|来源: Victor

最近在看spring的aop方面的知识,aop是基于动态代理模式实现的。所以顺便看了关于代理模式方面的知识点,现在把这些记录下来。
   代理模式有两种实现:静态代理和动态代理。
   代理模式涉及三个概念:委托(者)、代理(者)和主题接口。
    听一个故事,找着与代理模式涉及的三个概念相对应的内容。
    秀才作为一个委托者,委托(代理)媒婆去告诉姑娘自己的想法(比如要身材好、性感、知性、善良等),而媒婆必须要遵照秀才的约定的规则(接口)去告诉姑娘秀才的意愿。最终二者建立起感情,但是这个过程中两个人并没有参与进来,而是通过媒婆作为代理来传递信息。

 一、静态代理
    静态代理要求:代理类和被代理类都必须实现同一个接口,在代理类中实现事务操作等横切业务逻辑,被代理类中只保留核心业务逻辑。
    缺点:当方法很多时,势必要为每个方法都要进行代理操作,导致增加了代码的复杂度,所以静态代理不能胜任方法较多的情况。
    比如要在输出“HelloWorld”前打印一个字符串“Welcome”
A:先定义一个接口类

Java代码  收藏代码
  1. package proxy;  

  2. public interface HelloWorld {  

  3.    public void print();  

  4. //  public void say();  

  5. }  



B: 定义一个该接口的实现类
Java代码  收藏代码
  1. package proxy;    

  2. public class HelloWorldImpl implements HelloWorld{  

  3.    public void print(){  

  4.        System.out.println("HelloWorld");      

  5.    }      

  6. //  public void say(){      

  7. //      System.out.println("Say Hello!");      

  8. //  }      

  9. }  

 

C:定义一个静态代理类
Java代码  收藏代码
  1. package proxy;  

  2. public class StaticProxy implements HelloWorld{      

  3.    public HelloWorld helloWorld ;      

  4.    public StaticProxy(HelloWorld helloWorld){      

  5.        this.helloWorld = helloWorld;      

  6.    }      

  7.    public void print(){  

  8.        System.out.println("Welcome");      

  9.        //相当于回调      

  10.        helloWorld.print();      

  11.    }          

  12. //  public void say(){      

  13. //      //相当于回调      

  14. //      helloWorld.say();      

  15. //  }      

  16. }      



D: 一个测试类:
Java代码  收藏代码
  1. package proxy;    

  2. public class TestStaticProxy {      

  3.   public static void main(String[] args){      

  4.        HelloWorld helloWorld = new HelloWorldImpl();      

  5.        StaticProxy staticProxy = new StaticProxy(helloWorld);      

  6.        staticProxy.print();    

  7. //      staticProxy.say();      

  8.    }      

  9. }  



二、动态代理
   在java中要实现动态代理机制,则需要java.lang.reflect.InvocationHandler接口和java.lang.reflect.Proxy类的支持。
Java代码  收藏代码
  1.    public interface InvocationHandler{  

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

  3. }  


Java代码  收藏代码
  1. 参数:  

  2. proxy - 在其上调用方法的代理实例  

  3. method - 对应于在代理实例上调用的接口方法的 Method 实例。Method 对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。  

  4. args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。基本类型的参数被包装在适当基本包装器类(如 java.lang.Integer 或 java.lang.Boolean)的实例中。  


  Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类。
Java代码  收藏代码
  1. import java.lang.reflect.InvocationHandler ;  

  2. import java.lang.reflect.Proxy ;  

  3. import java.lang.reflect.Method ;  

  4. interface Subject{  

  5.    public String say(String name,int age) ;    // 定义抽象方法say  

  6. }  

  7. class RealSubject implements Subject{   // 实现接口  

  8.    public String say(String name,int age){  

  9.        return "姓名:" + name + ",年龄:" + age ;  

  10.    }  

  11. };  

  12. class MyInvocationHandler implements InvocationHandler{  

  13.    private Object obj ;  

  14.    public Object bind(Object obj){  

  15.        this.obj = obj ;    // 真实主题类  

  16.        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this) ;  

  17.    }  

  18.    public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{  

  19.        Object temp = method.invoke(this.obj,args) ;    // 调用方法  

  20.        return temp ;  

  21.    }  

  22. };  

  23. public class DynaProxyDemo{  

  24.    public static void main(String args[]){  

  25.        Subject sub = (Subject)new MyInvocationHandler().bind(new RealSubject()) ;  

  26.        String info = sub.say("曾召帅",23) ;  

  27.        System.out.println(info) ;  

  28.    }  

  29. };  


转自网络

相关问答

更多
  • 采用JAVA 动态代理设计模式设计的,目前主要应用于 事务,有了 Spring的 声明式事务可以 对程序员编码的代码量减少很多,不用每层的持久化方法都自己控制事务
  • 反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。   通常的代理服务器,只用于代理内部网络对Internet的连接请求,客户机必须指定代理服务器,并将本来要直接发送到Web服务器上的http请求发送到代理服务器中。由于外部网络上的主机并不会配置并使用这个代理服务器,普通代理服务器也被设计为在Internet上搜寻多个不确定的 ...
  • 你是准备学习使用 还是说研究它的底层实现机制这些东西? 如果只是使用 可以暂时不了解这些 ,你也没有这么多精力来了解这么多 你先将框架中的东西用熟练 然后再去了解这些也不迟 spring 的 IOC aop hibernate的 延迟加载 缓存 ,mvc这些学习都需要学习 其实你学习不学习这几个框架都可以对设计模式进行学习 设计模式在日常的版本开发中好处很多 而且在面试的时候 考官也会问设计模式方面的知识
  • 这是之前我的博客总结的: Proxy,代理模式:为其他对象提供一种代理以控制对这个对象的访问。  例如:经典的体现在Spring AOP切面中,Spring中利用了俩种代理类型。  其实,代理也分为静态和动态,但是我们一般常用动态,因为静态代理秀不起来 Adapter,适配器模式:将一类的接口转换成客户希望的另外一个接口,Adapter模式使得原本由于接口不兼容而不能一起工作那些类可以一起工作。 其中对象的适配器模式是各种结构型模式的起源,分为三种:类,对象,接口的适配器模式。 结一下三种适配器模式的应用场 ...
  • 装饰模式:以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案; 代理模式:给一个对象提供一个代理对象,并有代理对象来控制对原有对象的引用; 装饰模式应该为所装饰的对象增强功能;代理模式对代理的对象施加控制,并不提供对象本身的增强功能 二者的实现机制确实是一样的,可以看到他们的实例代码重复是很多的。但就语义上说,这两者的功能是相反的,模式的一个重要作用是简化其他程序员对你程序的理解, 你在一个地方写装饰,大家就知道这是在增加功能,你写代理,大家就知道是在限制, 虽然代码很可能相同,但如果你都叫他们装 ...
  • 很简单:对外部提供统一的接口方法,而代理类在接口中实现对真实类的附加操作行为,从而可以在不影响外部调用情况下,进行系统扩展。也就是说,我要修改真实角色的操作的时候,尽量不要修改他,而是在外部在“包”一层进行附加行为,即代理类。 例如:接口A有一个接口方法operator(),真是角色:RealA实现接口A,则必须实现接口方法operator()。客户端Client调用接口A的接口方法operator()。 现在新需求来了,需要修改RealA中的operator()的操作行为。怎么办呢?如果修改RealA就会 ...
  • 没有容器,你的图形看起来像这样: new CachedProductService( new ProductService()); 以下是使用简单注射器的示例: container.Register(); // Add caching conditionally based on a config switch if (ConfigurationManager.AppSettings["usecaching"] == "true" ...
  • 你似乎回答了自己的问题。 您应该使用更容易实现的用例。 如果在编译时没有为每个方法实现,则需要动态代理。 例如,模拟测试库使用动态代理,以便可以编写代码来一般地处理任何方法。 You have appeared to answer your own question. You should use the one which is easier to implement for your use case. You need to dynamic proxy when you do not have an ...
  • 首先,我会告诉我的答案,说我不相信有关于模式的任何硬性和快速规则 - 你从他们那里拿走你需要的东西,仅此而已。 我使用某些模式的方式无疑与另一个开发人员可能选择使用它们的方式不同。 那就是说,这是我对你的问题的看法。 代理模式解释 我知道Proxy设计模式的方式,你用它做两件事: 限制对特定对象实例的其他公共方法的访问 通过在第一次调用代理时实例化具体对象,然后将代理上的所有其他调用传递给代理创建的具体实例,防止其他昂贵且不必要的实例化成本。 也许RealService有一个你想要隐藏的方法doSometh ...
  • Castle的DynamicProxy就是这样做的: http : //www.castleproject.org/dynamicproxy/index.html 允许您提供拦截器: public void Intercept(IInvocation invocation) { // Call your other method first... then proceed invocation.Proceed(); } 您可以通过invocation.Method访问MethodInfo ...