黑马程序员技术交流社区
标题:
Java的动态代理技术
[打印本页]
作者:
870585356
时间:
2015-9-15 12:38
标题:
Java的动态代理技术
最近学习Java的动态代理技术,有点不懂,谁能举个例子详细说明下
作者:
瑞雪雄起
时间:
2015-9-15 12:38
(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 plaincopy
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("方法调用结束!" );
}
}
编写如下客户端测试代码:
[java] view plaincopy
class Client {
public static void main(String args[]) {
InvocationHandler handler = null;
AbstractUserDAO userDAO = new UserDAO();
handler = new DAOLogHandler(userDAO);
AbstractUserDAO proxy = null;
//动态创建代理对象,用于代理一个AbstractUserDAO类型的真实主题对象
proxy = (AbstractUserDAO)Proxy.newProxyInstance(AbstractUserDAO. class.getClassLoader(), new Class[]{AbstractUserDAO.class}, handler);
proxy.findUserById("张无忌"); //调用代理对象的业务方法
System.out.println("------------------------------");
AbstractDocumentDAO docDAO = new DocumentDAO();
handler = new DAOLogHandler(docDAO);
AbstractDocumentDAO proxy_new = null;
//动态创建代理对象,用于代理一个AbstractDocumentDAO类型的真实主题对象
proxy_new = (AbstractDocumentDAO)Proxy.newProxyInstance(Abstract DocumentDAO.class.getClassLoader(), new Class[]{AbstractDocumentDAO.class}, handler);
proxy_new.deleteDocumentById("D002"); //调用代理对象的业务方法
}
}
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2