zoukankan      html  css  js  c++  java
  • jdk动态代理(转)

    一旦这样绑定后,那么在进入代理对象方法调用的时候就会到HelloServiceProxy的invoke方法上,invoke方法有三个参数:第一个proxy是代理对象,第二个是当前调用那个方法,第三个是方法的参数。

    2、JDK动态代理

    这个动态代理还是不好理解的,我们先用一张图来表达它:

    好,它的意义是在我们访问一个对象的时候,动态代理可以给我们生成一个代理对象【占位】,它的作用是可以控制【真实对象】的访问。

    比方说,你是未成年人,我可能是是去访问你父母,由你父母来代替你访问你,那么你父母就是这个占位,而你就是真实对象。

    在JDK动态代理的要求是对象存在接口,所以真正的服务对象必须存在接口。

    假设我们现在有这样的一个服务,我给名字它会说: “hello ”+名字。

    那么我们先看看这个接口:

    [java] view plain copy
     
     print?
    1. public interface HelloService {  
    2.       
    3.     public void sayHello(String name);  
    4.       
    5. }  


    非常简单的接口,然后我们给出实现类:

    [java] view plain copy
     
     print?
    1. public class HelloServiceImpl implements HelloService{  
    2.     @Override  
    3.     public void sayHello(String name) {  
    4.         System.err.println("hello " + name);  
    5.     }  
    6. }  


    好,它实现了这个接口,并且实现了接口的方法。

    现在我们要变变,我希望

    在说:hello+name前打印:我准备说hello。

    之后打印:我说过hello了

    如果采用我们的代理对象【占位】显然实现起来非常容易,于是我们首先来生成这个【占位】

    [java] view plain copy
     
     print?
    1. import java.lang.reflect.InvocationHandler;  
    2. import java.lang.reflect.Method;  
    3. import java.lang.reflect.Proxy;  
    4.   
    5. public class HelloServiceProxy implements InvocationHandler {  
    6.   
    7.   
    8.     private Object target;    
    9.     /**  
    10.      * 绑定委托对象并返回一个【代理占位】 
    11.      * @param target 真实对象 
    12.      * @return  代理对象【占位】 
    13.      */    
    14.     public  Object bind(Object target, Class[] interfaces) {    
    15.         this.target = target;    
    16.         //取得代理对象    
    17.        <span style="color:#FF0000;"> return Proxy.newProxyInstance(target.getClass().getClassLoader(),    
    18.                 target.getClass().getInterfaces(), this);  </span>  
    19.     }    
    20.     
    21.     @Override    
    22.     /** 
    23.      * 同过代理对象调用方法首先进入这个方法. 
    24.      * @param proxy --代理对象 
    25.      * @param method -- 方法,被调用方法. 
    26.      * @param args -- 方法的参数 
    27.      */  
    28.     public Object invoke(Object proxy , Method method, Object[] args) throws Throwable {    
    29.         System.err.println("############我是JDK动态代理################");  
    30.         Object result = null;    
    31.         //反射方法前调用  
    32.         System.err.println("我准备说hello。");    
    33.         //反射执行方法  相当于调用target.sayHelllo;  
    34.         result=method.invoke(target, args);  
    35.         //反射方法后调用.  
    36.         System.err.println("我说过hello了");    
    37.         return result;    
    38.     }    
    39. }  


    这里的bind方法里面有句:

    [java] view plain copy
     
     print?
    1. Proxy.newProxyInstance(target.getClass().getClassLoader(),    
    2.                 target.getClass().getInterfaces(), this);   

    它的意义就是生成一个代理对象,这里有三个参数:第一个参数是类加载器,第二个参数是或者对象的接口(代理对象挂在那个接口下),第三个参数this代表当前HelloServiceProxy类,换句话说是使用HelloServiceProxy作为对象的代理。

    一旦这样绑定后,那么在进入代理对象方法调用的时候就会到HelloServiceProxy的invoke方法上,invoke方法有三个参数:第一个proxy是代理对象,第二个是当前调用那个方法,第三个是方法的参数。

    比方说,现在HelloServiceImpl对象(obj)用bind方法绑定后,返回其【占位】(proxy),我们在调用proxy.sa6yHello("张三"),那么它就会进入到HelloServiceProxy的invoke()方法。而invoke参数中第一个便是代理对象proxy,方法便是sayHello,参数是"张三"。那么我们就可以通过反射技术调度真实对象的方法。

    现在让我们看看测试代码:

    [java] view plain copy
     
     print?
    1. public class ProxyTest {  
    2.       
    3.     public static void main(String[] args) {   
    4.         HelloServiceProxy proxy = new HelloServiceProxy();  
    5.         HelloService service = new HelloServiceImpl();  
    6.         //绑定代理对象。  
    7.         service = (HelloService) proxy.bind(service, new Class[] {HelloService.class});  
    8.         //这里service经过绑定,就会进入invoke方法里面了。  
    9.         service.sayHello("张三");  
    10.     }  
    11. }  
    12.    


    好,我们运行一下,看一下结果。

    [plain] view plain copy
     
     print?
    1. ############我是JDK动态代理################  
    2. 我准备说hello。  
    3. hello 张三  
    4. 我说过hello了  


    好了,我们这样就可以看到动态代理。

    正确的理解反射和动态代理是我们进行MyBATIS底层的基础,尤其是动态代理,如果还不了解务必要多做上面的例子,切实理解好。

    本文转自:http://blog.csdn.net/ykzhen2015/article/details/50312651

  • 相关阅读:
    浏览器渲染页面
    递归求1-100之和
    border属性
    ES6 Class
    数组去重
    get、post请求
    对象冒充继承
    原型链继承
    实现JS数据拷贝
    【转】centos升级curl版本
  • 原文地址:https://www.cnblogs.com/panxuejun/p/6676558.html
Copyright © 2011-2022 走看看