java动态代理的实现

动态代理作为代理模式的一种扩展形式,广泛应用于框架(尤其是基于AOP的框架)的设计与开发,本文将通过实例来讲解Java动态代理的实现过程。

友情提示:本文略有难度,读者需具备代理模式相关基础知识

通常情况下,代理模式中的每一个代理类在编译之后都会生成一个class文件,代理类所实现的接口和所代理的方法都被固定,这种代理被称之为静态代理(Static Proxy)。那么有没有一种机制能够让系统在运行时动态创建代理类?答案就是本文将要介绍的动态代理(Dynamic Proxy)。动态代理是一种较为高级的代理模式,它在事务管理、AOP(Aspect-OrientedProgramming,面向方面编程)等领域都发挥了重要的作用。

在传统的代理模式中,客户端通过Proxy类调用RealSubject类的request()方法,同时还可以在代理类中封装其他方法(如preRequest()和postRequest()等)。如果按照这种方法使用代理模式,那么代理类和真实主题类都应该是事先已经存在的,代理类的接口和所代理方法都已明确指定,如果需要为不同的真实主题类提供代理类或者代理一个真实主题类中的不同方法,都需要增加新的代理类,这将导致系统中的类个数急剧增加,因此需要想办法减少系统中类的个数。动态代理可以让系统能够根据实际需要来动态创建代理类,让同一个代理类能够代理多个不同的真实主题类而且可以代理不同的方法。

从JDK 1.3开始,Java语言提供了对动态代理的支持,Java语言实现动态代理时需要用到位于java.lang.reflect包中的一些类,现简要说明如下:

      (1) Proxy类

Proxy类提供了用于创建动态代理类和实例对象的方法,它是所创建的动态代理类的父类,它最常用的方法如下:

  • public static Class<?> getProxyClass(ClassLoader loader,Class<?>... interfaces):该方法用于返回一个Class类型的代理类,在参数中需要提供类加载器并需要指定代理的接口数组(与真实主题类的接口列表一致)。
  • public static Object newProxyInstance(ClassLoader loader, Class<?>[]interfaces, InvocationHandler h):该方法用于返回一个动态创建的代理类的实例,方法中第一个参数loader表示代理类的类加载器,第二个参数interfaces表示代理类所实现的接口列表(与真实主题类的接口列表一致),第三个参数h表示所指派的调用处理程序类。

      (2) InvocationHandler接口

InvocationHandler接口是代理处理程序类的实现接口,该接口作为代理实例的调用处理者的公共父类,每一个代理类的实例都可以提供一个相关的具体调用处理者(InvocationHandler接口的子类)。在该接口中声明了如下方法:

  • public Object invoke(Objectproxy, Method method, Object[] args):该方法用于处理对代理类实例的方法调用并返回相应的结果,当一个代理实例中的业务方法被调用时将自动调用该方法。invoke()方法包含三个参数,其中第一个参数proxy表示代理类的实例,第二个参数method表示需要代理的方法,第三个参数args表示代理方法的参数数组。

        动态代理类需要在运行时指定所代理真实主题类的接口,客户端在调用动态代理对象的方法时,调用请求会将请求自动转发给InvocationHandler对象的invoke()方法,由invoke()方法来实现对请求的统一处理。

下面通过一个简单实例来学习如何使用动态代理模式:


Sunny软件公司欲为公司OA系统数据访问层DAO增加方法调用日志,记录每一个方法被调用的时间和调用结果,现使用动态代理进行设计和实现。

本实例完整代码如下所示:

[java] view plain copy

  1. import java.lang.reflect.Proxy;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.InvocationTargetException;
  4. import java.lang.reflect.Method;
  5. import java.util.Calendar;
  6. import java.util.GregorianCalendar;
  7. //抽象UserDAO:抽象主题角色
  8. interface AbstractUserDAO {
  9. public Boolean findUserById(String userId);
  10. }
  11. //抽象DocumentDAO:抽象主题角色
  12. interface AbstractDocumentDAO {
  13. public Boolean deleteDocumentById(String documentId);
  14. }
  15. //具体UserDAO类:真实主题角色
  16. class UserDAO implements AbstractUserDAO {
  17. public Boolean findUserById(String userId) {
  18. if (userId.equalsIgnoreCase("张无忌")) {
  19. System.out.println("查询ID为" + userId + "的用户信息成功!");
  20. return true;
  21. }
  22. else {
  23. System.out.println("查询ID为" + userId + "的用户信息失败!");
  24. return false;
  25. }
  26. }
  27. }
  28. //具体DocumentDAO类:真实主题角色
  29. class DocumentDAO implements AbstractDocumentDAO {
  30. public Boolean deleteDocumentById(String documentId) {
  31. if (documentId.equalsIgnoreCase("D001")) {
  32. System.out.println("删除ID为" + documentId + "的文档信息成功!");
  33. return true;
  34. }
  35. else {
  36. System.out.println("删除ID为" + documentId + "的文档信息失败!");
  37. return false;
  38. }
  39. }
  40. }
  41. //自定义请求处理程序类
  42. class DAOLogHandler implements InvocationHandler {
  43. private Calendar calendar;
  44. private Object object;
  45. public DAOLogHandler() {
  46. }
  47. //自定义有参构造函数,用于注入一个需要提供代理的真实主题对象
  48. public DAOLogHandler(Object object) {
  49. this.object = object;
  50. }
  51. //实现invoke()方法,调用在真实主题类中定义的方法
  52. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  53. beforeInvoke();
  54. Object result = method.invoke(object, args); //转发调用
  55. afterInvoke();
  56. return null;
  57. }
  58. //记录方法调用时间
  59. public void beforeInvoke(){
  60. calendar = new GregorianCalendar();
  61. int hour = calendar.get(Calendar.HOUR_OF_DAY);
  62. int minute = calendar.get(Calendar.MINUTE);
  63. int second = calendar.get(Calendar.SECOND);
  64. String time = hour + ":" + minute + ":" + second;
  65. System.out.println("调用时间:" + time);
  66. }
  67. public void afterInvoke(){
  68. System.out.println("方法调用结束!" );
  69. }
  70. }

编写如下客户端测试代码:

[java] view plain copy

  1. class Client {
  2. public static void main(String args[]) {
  3. InvocationHandler handler = null;
  4. AbstractUserDAO userDAO = new UserDAO();
  5. handler = new DAOLogHandler(userDAO);
  6. AbstractUserDAO proxy = null;
  7. //动态创建代理对象,用于代理一个AbstractUserDAO类型的真实主题对象
  8. proxy = (AbstractUserDAO)Proxy.newProxyInstance(AbstractUserDAO. class.getClassLoader(), new Class[]{AbstractUserDAO.class}, handler);
  9. proxy.findUserById("张无忌"); //调用代理对象的业务方法
  10. System.out.println("------------------------------");
  11. AbstractDocumentDAO docDAO = new DocumentDAO();
  12. handler = new DAOLogHandler(docDAO);
  13. AbstractDocumentDAO proxy_new = null;
  14. //动态创建代理对象,用于代理一个AbstractDocumentDAO类型的真实主题对象
  15. proxy_new = (AbstractDocumentDAO)Proxy.newProxyInstance(Abstract DocumentDAO.class.getClassLoader(), new Class[]{AbstractDocumentDAO.class}, handler);
  16. proxy_new.deleteDocumentById("D002"); //调用代理对象的业务方法
  17. }
  18. }

编译并运行程序,输出结果如下:


调用时间:13:47:14

查询ID为张无忌的用户信息成功!

方法调用结束!

------------------------------

调用时间:13:47:14

删除ID为D002的文档信息失败!

方法调用结束!

通过使用动态代理,我们可以实现对多个真实主题类的统一代理和集中控制。

注:JDK中提供的动态代理只能代理一个或多个接口,如果需要动态代理具体类或抽象类,可以使用CGLib(Code Generation Library)等工具,CGLib是一个功能较为强大、性能和质量也较好的代码生成包,在许多AOP框架中都得以广泛应用,大家可以自行查阅相关资料来学习CGLib。

时间: 2024-10-04 06:13:23

java动态代理的实现的相关文章

理解java动态代理

java动态代理是java语言的一项高级特性.在平时的项目开发中,可能很难遇到动态代理的案例.但是动态代理在很多框架中起着不可替代的作用,例如Spring的AOP.今天我们就聊一聊java动态代理的实现原理. jdk对于动态代理的支持主要依赖于两个类:Proxy和InvocationHandler.我们先看一下类图. Subject类是主题类,定义了我要做什么.我们需要代理的类即实现Subject接口的RealSubject. 1.InvocationHandler InvocationHand

java动态代理机制

首先了解代理设计模式,其思想是为其他对象提供一种代理以控制对这个对象的访问. java动态代理就是遵循这种思想,spring中的AOP实现原理就是java的动态代理. 在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface).另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的. 每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通

java动态代理

要想了解Java动态代理,首先要了解什么叫做代理,熟悉设计模式的朋友一定知道在Gof总结的23种设计模式中,有一种叫做代理(Proxy)的对象结构型模式,动态代理中的代理,指的就是这种设计模式. 在我看来所谓的代理模式,和23种设计模式中的"装饰模式"是一个东西.23种设计模式中将它们作为两种模式,网上也有些文章讲这两种模式的异同,从细节来看,确实可以人为地区分这两种模式,但是抽象到一定高度后,我认为这两种模式是完全一样的.因此学会了代理模式,也就同时掌握了装饰模式. 代理模式 代理模

java 动态代理示例,带主要注释

Java proxy是基于反射,仅仅支持基于接口的动态代理. java 动态代理是一切架构的基础,必须了解. 废话少说,先上代码获得感性认识. 示例代码有主要注释. 接口: public interface Subject { String hello(String name); void say();} 接口实现: public class ImpSubject implements Subject { @Override public String hello(String name){ r

java动态代理原理及解析

代理:设计模式 代理模式是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个真实对象的访问.代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理. 通过代理层这一中间层,有效的控制对于真实委托类对象的直接访问,同时可以实现自定义的控制策略(Spring的AOP机制),设计上获得更大的灵活性. java动态代理的类和接口(jdk1.6源码) 1,java.lang.reflect.Proxy:动态代理机制的主类,提供一组静态方法为一组接口动态的生成对

彻底理解JAVA动态代理

注:本文转自 http://www.cnblogs.com/flyoung2008/archive/2013/08/11/3251148.html 代理设计模式 定义:为其他对象提供一种代理以控制对这个对象的访问. 代理模式的结构如下图所示. 动态代理使用 java动态代理机制以巧妙的方式实现了代理模式的设计理念. 代理模式示例代码 public interface Subject { public void doSomething(); } public class RealSubject i

JAVA动态代理详解

1.什么是代理 代理模式是常用的Java 设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等. 2.什么是动态代理 在程序运行时,运用反射机制动态创建代理实例对象.JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理. 相关类与接口 java.lang.reflect.Proxy:这是 Java 动态代理机制的主类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象. //

java 动态代理 , 多看看。 多用用。

import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import java.lang.reflect.Method; //抽象角色:java动态代理的实现目前只支持接口,不支持抽象类 interface BusinessFoo { void foo(); } interface BusinessBar { String bar(String message); } //真实角色:真正实现业务逻辑方

java动态代理框架

java动态代理是一个挺有意思的东西,他有时候可以被使用的很灵活.像rpc的调用,调用方只是定义的一个接口,动态代理让他匹配上对应的不同接口:mybatis内部的实现,编码时,只是实现了mapper层的接口和sql的xml的配置,动态代理把他们连起来.记得之前在一家公司,他们使用thrift做rpc的解决方案,每个项目都得管理thrift的连接和关闭,代码考来考去,在spring下还得不断new对象.后来参照mybatis的实现方式,使用动态代理,做成spring注入的方式,方便很多,程序员只需