简介

代理模式即Proxy Pattern,23种java常用设计模式之一。其定义为:对其他对象提供一种代理以控制对这个对象的访问。


UML类图


静态代理

目标接口

  1. public interface Subject {
  2.  
  3. public void execute();
  4.  
  5. }

目标实现类

  1. public class RealSubject implements Subject {
  2.  
  3. private String a;
  4.  
  5. public RealSubject(String a) {
  6. this.a = a;
  7. }
  8.  
  9. @Override
  10. public void execute() {
  11. System.out.println("do biz, " + a);
  12. }
  13.  
  14. }

代理类

  1. public class StaticProxy implements Subject {
  2.  
  3. private Subject subject;
  4.  
  5. public StaticProxy(Subject subject) {
  6. this.subject = subject;
  7. }
  8.  
  9. @Override
  10. public void execute() {
  11. System.out.println("before executing");
  12. subject.execute();
  13. System.out.println("after executing");
  14. }
  15.  
  16. }

测试类

  1. public class StaticProxyTest {
  2.  
  3. public static void main(String[] args) {
  4. Subject subject = new RealSubject("hello");
  5. StaticProxy proxy = new StaticProxy(subject);
  6. proxy.execute();
  7. }
  8.  
  9. }

运行结果输出

  1. before executing
  2. do biz, hello
  3. after executing

通过这种方法,利用代理类在目标类执行核心方法前后添加了相应辅助逻辑。

但值得注意的是,当在代码阶段规定这种代理关系,StaticProxy类通过编译器编译成.class文件,当系统运行时,此.class已经存在了。这种静态的代理模式固然在访问无法访问的资源,增强现有的接口业务功能方面有很大的优点,但是大量使用这种静态代理,会使我们系统内类的规模增大,且不易维护;并且由于StaticProxy和RealSubject的功能本质上是相同的,StaticProxy只是起到了中介的作用,这种代理在系统中的存在,会导致系统结构比较臃肿和松散。


JDK动态代理

JDK从1.3版本起自带的动态代理机制由java.lang.reflect.Proxy实现,使用时必须创建一个实现了java.lang.reflect.InvocationHandler接口的动态代理类,该接口只有一个方法:

  1. Object invoke(Object proxy,
  2. Method method,
  3. Object[] args)
  4. throws Throwable

 参数:

 proxy - 在其上调用方法的代理实例method - 对应于在代理实例上调用的接口方法的 Method 实例。

 Method 对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。

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

动态代理工作的基本模式就是将自己的方法功能的实现交给 InvocationHandler角色,外界对Proxy角色中的每一个方法的调用,Proxy角色都会交给InvocationHandler来处理,而InvocationHandler则调用具体对象角色的方法。如下图所示:

再来看Proxy如何创建出一个代理对象,常用的方法为:

  1. public static Object newProxyInstance(ClassLoader loader,
  2. Class<?>[] interfaces,
  3. InvocationHandler h)
  4. throws IllegalArgumentException
  5.  
  6. 参数:
    loader - 定义代理类的类加载器
    interfaces - 代理类要实现的接口列表
    h - 指派方法调用的调用处理程序该方法返回的对象是实现了参数interfaces中指明的接口的子类对象,因此强制要求目标类必须是接口。
  7.  
  8. 接下来通过示例代码演示动态代理的使用方式
  9.  
  10. 目标接口
  1. public interface Subject {
  2.  
  3. public void doBiz();
  4.  
  5. }

目标实现类

  1. public class RealSubject implements Subject {
  2.  
  3. private String a;
  4.  
  5. public RealSubject(String a) {
  6. this.a = a;
  7. }
  8.  
  9. @Override
  10. public void doBiz() {
  11. System.out.println("do biz, " + a);
  12. }
  13.  
  14. }

动态代理类

  1. import java.lang.reflect.InvocationHandler;
  2. import java.lang.reflect.Method;
  3.  
  4. public class DynamicProxy implements InvocationHandler {
  5.  
  6. private Object target;
  7.  
  8. public DynamicProxy(Object target) {
  9. this.target = target;
  10. }
  11.  
  12. @Override
  13. public Object invoke(Object proxy, Method method, Object[] args)
  14. throws Throwable {
  15. System.out.println("before executing");
  16. Object result = method.invoke(target, args);
  17. System.out.println("after executing");
  18. return result;
  19. }
  20.  
  21. }

测试类

  1. import java.lang.reflect.InvocationHandler;
  2. import java.lang.reflect.Proxy;
  3.  
  4. public class DynamicProxyTest {
  5.  
  6. public static void main(String[] args) {
  7. Subject subject = new RealSubject("hello");
  8. InvocationHandler handler = new DynamicProxy(subject);
  9. Subject proxy = (Subject) Proxy.newProxyInstance(
  10. Subject.class.getClassLoader(), new Class[] { Subject.class },
  11. handler); // 由于第二个参数传入了Subject.class,因此返回的代理对象实现了该接口,可以转换为Subject对象
  12. System.out.println("proxy = " + proxy.getClass().getName());
  13. if (proxy instanceof Proxy) {
  14. System.out.println("proxy implements java.lang.reflect.Proxy");
  15. }
  16. if (proxy instanceof Subject) {
  17. System.out.println("proxy implements Subject");
  18. }
  19. proxy.doBiz();
  20. }
  21.  
  22. }

运行结果输出

  1. proxy = com.sun.proxy.$Proxy0
  2. proxy implements java.lang.reflect.Proxy
  3. proxy implements Subject
  4. before executing
  5. do biz, hello
  6. after executing

第一行输出为代理对象的名称,第二、三行表明代理对象实现了java.lang.reflect.Proxy接口和Subject接口,后面的打印结果与静态代理时一致。

所以JDK动态代理有个显著的特点(限制):某个类必须有实现的接口,而生成的代理类也只能代理某个类接口定义的方法。下面介绍的Cglib动态代理就不存在此类限制。


Cglib动态代理

Cglib是一个第三方类库,用于创建动态代理,包括Spring AOP在内多个框架都内部集成了Cglib,而它底层也利用了ASM操纵字节码。Cglib类库的框架图如下:

使用Cglib创建动态代理与JDK原生的动态代理不同之处在于它并不强制要求目标类为接口,因此可以对于普通Java类进行代理。

使用时需要在pom.xml配置两个依赖:

  1. <dependency>
  2. <groupId>cglib</groupId>
  3. <artifactId>cglib</artifactId>
  4. <version>2.2.2</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>asm</groupId>
  8. <artifactId>asm</artifactId>
  9. <version>3.3.1</version>
  10. </dependency>

动态代理类需要实现net.sf.cglib.proxy.MethodInterceptor接口(等价于JDK动态代理中的InvocationHandler接口),其中只有一个方法:

public Object intercept(Object object, Method method, Object[] args,
MethodProxy proxy) throws Throwable

参数:

 object - 被代理的对象。

 method - 被代理对象的方法。

 args - 包含传入代理实例上方法调用的参数值的对象数组。

 proxy - 代理对象。

接下来通过示例代码演示Cglib动态代理的使用方式

目标类

  1. public class RealSubject {
  2.  
  3. private String a;
  4.  
  5. public RealSubject(String a) {
  6. this.a = a;
  7. }
  8.  
  9. public void doBiz() {
  10. System.out.println("do biz, " + a);
  11. }
  12.  
  13. }

代理类

  1. import java.lang.reflect.Method;
  2.  
  3. import net.sf.cglib.proxy.MethodInterceptor;
  4. import net.sf.cglib.proxy.MethodProxy;
  5.  
  6. public class CglibProxy implements MethodInterceptor {
  7.  
  8. @Override
  9. public Object intercept(Object object, Method method, Object[] args,
  10. MethodProxy proxy) throws Throwable {
  11. System.out.println("before executing");
  12. Object result = proxy.invokeSuper(object, args);
  13. System.out.println("after executing");
  14. return result;
  15. }
  16.  
  17. }

目标类工厂

  1. import net.sf.cglib.proxy.Enhancer;
  2.  
  3. public class RealSubjectFactory {
  4.  
  5. public static RealSubject getInstance(CglibProxy proxy) {
  6. Enhancer enhancer = new Enhancer();
  7. enhancer.setSuperclass(RealSubject.class);
  8. enhancer.setCallback(proxy);
  9. RealSubject subject = (RealSubject) enhancer.create(
  10. new Class[] { String.class }, new Object[] { "hello" }); // 返回值是RealSubject的子类对象;如果目标类的构造方法不含参数,则这儿无需传入create()方法的参数
    return subject;
  11. }
  12.  
  13. }

测试类

  1. public class CglibProxyTest {
  2.  
  3. public static void main(String[] args) {
  4. CglibProxy proxy = new CglibProxy();
  5. RealSubject subject = RealSubjectFactory.getInstance(proxy);
  6. subject.doBiz();
  7. }
  8.  
  9. }

运行结果输出

  1. before executing
  2. do biz, hello
  3. after executing

输出结果与静态代理一致。


Javassist动态代理

此外,利用javassist字节码生成框架也可以以类似的方式实现动态代理,使用时需要在pom.xml配置依赖:

  1. <dependency>
  2. <groupId>org.javassist</groupId>
  3. <artifactId>javassist</artifactId>
  4. <version>3.18.1-GA</version>
  5. </dependency>

接下来直接展示示例代码。

目标接口

  1. public interface Subject {
  2.  
  3. public void doBiz();
  4.  
  5. }

目标实现类

  1. public class RealSubject implements Subject {
  2.  
  3. private String a;
  4.  
  5. public RealSubject(String a) {
  6. this.a = a;
  7. }
  8.  
  9. @Override
  10. public void doBiz() {
  11. System.out.println("do biz, " + a);
  12. }
  13.  
  14. }

代理类

  1. import java.lang.reflect.Method;
  2.  
  3. import javassist.util.proxy.MethodHandler;
  4.  
  5. public class JavassistProxy implements MethodHandler {
  6.  
  7. private Object target;
  8.  
  9. public JavassistProxy(Object target) {
  10. this.target = target;
  11. }
  12.  
  13. @Override
  14. public Object invoke(Object proxy, Method method, Method method2,
  15. Object[] args) throws Throwable {
  16. System.out.println("before executing");
  17. Object result = method.invoke(target, args);
  18. System.out.println("after executing");
  19. return result;
  20. }
  21.  
  22. }

测试类

  1. import javassist.util.proxy.ProxyFactory;
  2. import javassist.util.proxy.ProxyObject;
  3.  
  4. public class JavassistProxyTest {
  5.  
  6. public static void main(String[] args) throws InstantiationException,
  7. IllegalAccessException {
  8. Subject subject = new RealSubject("hello");
  9. ProxyFactory proxyFactory = new ProxyFactory();
  10. proxyFactory.setInterfaces(new Class[] { Subject.class });
  11. Subject proxy = (Subject) proxyFactory.createClass().newInstance();
  12. ((ProxyObject) proxy).setHandler(new JavassistProxy(subject));
  13. proxy.doBiz();
  14. }
  15.  
  16. }

运行结果输出

  1. before executing
  2. do biz, hello
  3. after executing

输出结果与静态代理一致。


REFERENCES

[1] http://jnb.ociweb.com/jnb/jnbNov2005.html

[2] http://www.cnblogs.com/flyoung2008/archive/2013/08/11/3251148.html

[3] http://www.cnblogs.com/xiaoluo501395377/p/3383130.html

[4] http://blog.csdn.net/dreamrealised/article/details/12885739

[5] http://blog.csdn.net/jackiehff/article/details/8621517

[6] https://dzone.com/articles/cglib-missing-manual

[7] http://www.360doc.com/content/14/0801/14/1073512_398598312.shtml

[8] http://javatar.iteye.com/blog/814426


为尊重原创成果,如需转载烦请注明本文出处:http://www.cnblogs.com/fernandolee24/p/6182924.html ,特此感谢

Java代理模式汇总的更多相关文章

  1. Java代理模式

    java代理模式及动态代理类 1.      代理模式 代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目 ...

  2. Java代理模式示例程序

    Java代理模式示例程序 当然不是我想出来的,是我看的一个网上教程里的. 模拟的是一个对电脑公司的代理 真实类的接口: public interface SaleComputer { public S ...

  3. java 代理模式 总结

    1.前言 最近舍友去面试遇到了关于java代理模式的问题. 我虽然知道怎么使用,但是没有做过正经的总结,因此有了这篇随笔,好好总结一下三大代理模式底层原理. 事实上,在开发项目的时候,基本用不上代理, ...

  4. 浅谈java代理模式

    讲解java代理模式 目录 讲解java代理模式 何谓代理模式 静态代理 动态代理 JDK动态代理 CGLIB动态代理 何谓代理模式 代理模式,即Proxy Pattern,23种java常用设计模式 ...

  5. Java代理模式/静态代理/动态代理

    代理模式:即Proxy Pattern,常用的设计模式之一.代理模式的主要作用是为其他对象提供一种代理以控制对这个对象的访问. 代理概念 :为某个对象提供一个代理,以控制对这个对象的访问. 代理类和委 ...

  6. JAVA代理模式与动态代理模式

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

  7. java 代理模式一: 静态代理

    代理模式: 代理模式的作用:为其他对象提供一种代理以控制对 特定对象  的访问. 某种情况下,一个客户不想或者直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用:通过代理对象引用. ...

  8. 18 java 代理模式 (转)

    静态代理 1.新建一个接口,这个接口所提供的方法是关于数据库操作的 public interface EmployeeDao { public void updateSalary(); } 2.建一个 ...

  9. JAVA 代理模式(Proxy)

    1.代理模式 代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 代理模式一般涉 ...

随机推荐

  1. ETHREAD APC

    ETHREAD APC <寒江独钓>内核学习笔记(4) 继续学习windows 中和线程有关系的数据结构: ETHREAD.KTHREAD.TEB 1. 相关阅读材料 <window ...

  2. 应用内支付(IAP)可加入三方支付

    Windows Phone 放开政策 - 应用内支付(IAP)可加入三方支付   Windows Phone 应用商店在 今年(2013)11月04号 修改了商店政策 允许公司账户的应用使用三方支付S ...

  3. 由ASP.NET所谓前台调用后台、后台调用前台想到HTTP

    由ASP.NET所谓前台调用后台.后台调用前台想到HTTP 在由ASP.NET所谓前台调用后台.后台调用前台想到HTTP——理论篇中描述了一下ASP.NET新手的三个问题及相关的HTTP协议内容,在由 ...

  4. ios学习笔记第四天之官方文档总结

    start developing ios app today. 官方文档的体系结构为: 各层的主要框架图: objectice-c是动态语言 Objective-C 为 ANSI C 添加了下述语法和 ...

  5. Asp.Net请求响应过程

    Asp.Net请求响应过程 在之前,我们写了自己的Asp.Net框架,对整个流程有了一个大概的认识.这次我们来看一下Asp.Net整个请求处理过程是怎么样的. 浏览器封装请求报文,发送请求到达服务器, ...

  6. MS数据库优化查询最常见的几种方法

    1.没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷) 2.I/O吞吐量小,形成了瓶颈效应. 3.没有创建计算列导致查询不优化. 4.内存不足 5.网络速度慢 6.查询出的数据量过大 ...

  7. C#实战Microsoft Messaging Queue(MSMQ)

    C#实战Microsoft Messaging Queue(MSMQ)消息队列(干货) 前言 在使用MSMQ之前,我们需要自行安装消息队列组件!(具体安装方法大家自己搜一下吧) 采用MSMQ带来的好处 ...

  8. android 4.2 源码在64位Ubuntu编译

    1.获取Android源代码 Android官网给出了从网上下载源代码的方法,具体流程如下网址所示:http://source.android.com/source/downloading.html ...

  9. 分享Mvc3+NInject+EF+LigerUI权限系统Demo

    前段时间时不时看到有园友的分享权限系统,于是本人突发奇想,也想写一个玩玩,就利用晚上时间,陆陆续续花了一周多样子,写了如今这个权限系统,这个权限系统具有 组织结构.用户.角色.菜单,组织结构下挂用户, ...

  10. 3364 Lanterns (异或方程组高斯消元)

    基本思路.首先构造一个n*(m+1)的矩阵,同时标记一个行数row,row从零开始,然后找出每一列第一个非零的数,和第row行互换, 然后对row到n行,异或运算.最终的结果为2^(m-row) #i ...