动态代理作为代理模式的一种扩展形式,广泛应用于框架(尤其是基于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类提供了用于创建动态代理类和实例对象的方法,它是所创建的动态代理类的父类,它最常用的方法如下:
(2) InvocationHandler接口
InvocationHandler接口是代理处理程序类的实现接口,该接口作为代理实例的调用处理者的公共父类,每一个代理类的实例都可以提供一个相关的具体调用处理者(InvocationHandler接口的子类)。在该接口中声明了如下方法:
public Object invoke(Objectproxy, Method method, Object[] args):该方法用于处理对代理类实例的方法调用并返回相应的结果,当一个代理实例中的业务方法被调用时将自动调用该方法。invoke()方法包含三个参数,其中第一个参数proxy表示代理类的实例,第二个参数method表示需要代理的方法,第三个参数args表示代理方法的参数数组。
动态代理类需要在运行时指定所代理真实主题类的接口,客户端在调用动态代理对象的方法时,调用请求会将请求自动转发给InvocationHandler对象的invoke()方法,由invoke()方法来实现对请求的统一处理。
下面通过一个简单实例来学习如何使用动态代理模式:
Sunny软件公司欲为公司OA系统数据访问层DAO增加方法调用日志,记录每一个方法被调用的时间和调用结果,现使用动态代理进行设计和实现。
本实例完整代码如下所示:
import java.lang.reflect.Proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Calendar; import java.util.GregorianCalendar; //抽象UserDAO:抽象主题角色 interface AbstractUserDAO { public Boolean findUserById(String userId); } //抽象DocumentDAO:抽象主题角色 interface AbstractDocumentDAO { public Boolean deleteDocumentById(String documentId); } //具体UserDAO类:真实主题角色 class UserDAO implements AbstractUserDAO { public Boolean findUserById(String userId) { if (userId.equalsIgnoreCase("张无忌")) { System.out.println("查询ID为" + userId + "的用户信息成功!"); return true; } else { System.out.println("查询ID为" + userId + "的用户信息失败!"); return false; } } } //具体DocumentDAO类:真实主题角色 class DocumentDAO implements AbstractDocumentDAO { public Boolean deleteDocumentById(String documentId) { if (documentId.equalsIgnoreCase("D001")) { System.out.println("删除ID为" + documentId + "的文档信息成功!"); return true; } else { System.out.println("删除ID为" + documentId + "的文档信息失败!"); return false; } } } //自定义请求处理程序类 class DAOLogHandler implements InvocationHandler { private Calendar calendar; private Object object; public DAOLogHandler() { } //自定义有参构造函数,用于注入一个需要提供代理的真实主题对象 public DAOLogHandler(Object object) { this.object = object; } //实现invoke()方法,调用在真实主题类中定义的方法 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { beforeInvoke(); Object result = method.invoke(object, args); //转发调用 afterInvoke(); return null; } //记录方法调用时间 public void beforeInvoke(){ calendar = new GregorianCalendar(); int hour = calendar.get(Calendar.HOUR_OF_DAY); int minute = calendar.get(Calendar.MINUTE); int second = calendar.get(Calendar.SECOND); String time = hour + ":" + minute + ":" + second; System.out.println("调用时间:" + time); } public void afterInvoke(){ System.out.println("方法调用结束!" ); } }