黑马程序员技术交流社区

标题: 关于代理的一个问题 [打印本页]

作者: 杜成龙    时间: 2013-9-25 21:17
标题: 关于代理的一个问题
在代理中有个问题一直想不通,这里向大家请教一下!
我们知道,想创建某个目标类的代理类,首先要让这个代理类和这个目标类实现相同的接口,老师讲这么做就是让它们具有相同的方法,
我的问题就在这儿,目标类实现了某个接口后,它不仅有接口中的方法,同时它还可能有自己特有的方法,而我们的代理类实现了相同的
这个接口,按说只会有接口中的这些方法,怎么会有目标类中特有的方法呢?请大家指点一下,谢谢啦?



作者: 暮雨    时间: 2013-9-25 21:27
我想你还是不太明白动态代理的原理,这样吧,我把我以前写的一个博客给你拿过来吧,希望能帮到你。
博客地址是:http://blog.csdn.net/dreamskyforjava/article/details/9672131

JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,在并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一起。而Proxy为InvocationHandler实现类动态创建一个符合某一接口的代理实例。下面我就用一个实例演示面向切面编程中动态代理的过程。

首先把需要的类引入进来
User类
  1.     public class User {  
  2.       
  3.         private String userName;  
  4.         private String password;  
  5.          
  6.         public String getUserName() {  
  7.             return userName;  
  8.         }  
  9.         public void setUserName(String userName) {  
  10.             this.userName = userName;  
  11.         }  
  12.         public String getPassword() {  
  13.             return password;  
  14.         }  
  15.         public void setPassword(String password) {  
  16.             this.password = password;  
  17.         }  
  18.          
  19.     }</span>  


  20. 接口UserDao:
  21. [java] view plaincopyprint?

  22.     <span style="font-family:Times New Roman;"><span style="font-size:18px;">package com.spring.dao;  
  23.       
  24.     import com.spring.model.User;  
  25.       
  26.     public interface UserDao {  
  27.       
  28.         public void save(User u);  
  29.          
  30.         public void delete();  
  31.     }</span>  
  32.     </span>  


  33. UserDaoImpl:
  34. [java] view plaincopyprint?

  35.     <span style="font-family:Times New Roman;font-size:18px;">package com.spring.dao.impl;  
  36.       
  37.     import com.spring.dao.UserDao;  
  38.     import com.spring.model.User;  
  39.       
  40.     public class UserDaoImpl implements UserDao{  
  41.       
  42.         public void save(User u) {  
  43.       
  44.             System.out.println("user saved !");  
  45.         }  
  46.          
  47.         public void delete()  
  48.         {  
  49.             System.out.println("delete ok !");  
  50.         }  
  51.       
  52.     }
复制代码
好了,下面我们要做的事就是写出一个UserDaoImpl类的动态代理类,这个代理类实现的功能是在调用UserDaoImpl类方法的时候提示该方法已经开始执行的语句。代理类LogInterceptor,他实现了InvocationHandler接口
  1. import java.lang.reflect.InvocationHandler;  
  2. import java.lang.reflect.Method;  
  3.   
  4. public class LogInterceptor implements InvocationHandler {  
  5.   
  6.     private Object target; //接收被代理类的对象  
  7.       
  8.     public Object getTarget() {  
  9.         return target;  
  10.     }  
  11.   
  12.     public void setTarget(Object target) {  
  13.         this.target = target;  
  14.     }  
  15.   
  16.     public void beforeMethod(Method m)  
  17.     {  
  18.         System.out.println(m.getName()+" start !");  
  19.     }  
  20.       
  21.     public Object invoke(Object proxy, Method method, Object[] args)   
  22.             throws Throwable {</span><span style="font-family:Times New Roman;">  
  23.                  <span style="font-size:14px;">beforeMethod(method);  
  24.         method.invoke(target, args);  
  25.         return null;</span>  
  26.     }  
  27. }
复制代码
在接口方法invoke(Object proxy, Methodmethod, Object[] args)里,将目标类实例传给method.invoke()方法,通过反射调用目标类方法。最后就是生成代理类对象并初始化,调用方法查看结果,完成切面编程的过程。以junit进行单元测试,代码如下
public void taestProxy()  
    {  
        UserDao userDao = new UserDaoImpl();  
        LogInterceptor li = new LogInterceptor();  
        li.setTarget(userDao);  
                //为编织了目标业务类逻辑和横切逻辑的LogInterceptor创建代理类  
                UserDao proxy = (UserDao)Proxy.newProxyInstance(userDao.getClass().getClassLoader(),   
                                 userDao.getClass().getInterfaces(), li);</span><span style="font-family:Times New Roman;font-size:18px;">  
        proxy.save(new User());  
        proxy.delete();  
    }
上面的代码完成了业务类代码和横切代码编织和接口代理实例生成的工作,其中在li.setTarget(userDao)处,我们将LogInterceptor实例编织为一个包含业务逻辑和横切逻辑实例,然后在newProxyInstance处,通过Proxy的静态方法newProxyInstance()为融合了业务类逻辑和横切逻辑的LogInterceptor创建一个UserDao接口的代理实例,该方法的第一个入参为类加载器,第二个入参为创建的代理实例所要实现的一组接口,第三个参数是整合了业务逻辑和横切逻辑的编织器对象。简言之这三个参数分别是UserDaoImpl的类加载器、UserDao接口、实现了代理的类LogInterceptor对象,此时UserDaoImpl是被代理的对象

作者: 杜成龙    时间: 2013-9-26 14:58
非常感谢!




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2