黑马程序员技术交流社区

标题: 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