java语言代理模式

来源:互联网 发布:淘宝运营正确思路流程 编辑:程序博客网 时间:2024/05/18 01:10

代理模式和JDK的动态代理技术学习笔记 01

            一直对jdk的动态代理技术认识很模糊,花了几天时间研究它的实现原理。本文章涉及到累的加载以及java反射机制方面的知识。如果对这两方面有一定的理解
的话会更加容易明白。

        代理模式:如果你学过或者知道装饰者模式,那么可以说你很容易就会掌握代理模式。
这两个模式很相似(个人的见解),都是通过传递一个需要被代理的对象(target)来
增强该类的功能。

  代理模式的的本质就是传递一个目标对象(target)的引用来进行目标对象的本身具有的操作,但是同时
代理类会在执行目标对象(target)本身具有的方法之前和之后添加一些额外的操作,以达到增强目标对象
(target)功能的目的。

  对于java语言来说,代理模式分为两种:1、静态代理;2、动态代理(目前主要包括JDK自身具备的动
态代理技术和cglib技术)

  静态代理很好理解,下面结合代码来讲述:


    先定义一个简单的接口:

package test.proxy;    public interface BookFacade {//添加书本的方法void addBook();    }

    然后就是这个接口的实现类:
package test.proxy;    public class BookFacadeImpl implements BookFacade{@Overridepublic void addBook() {System.out.println("添加书本");}    }


    然后就是这个接口某个实现类的代理类:
package test.proxy;    public class BookFacadeProxy {        //目标类的一个引用private BookFacade target;public BookFacadeProxy(BookFacade target){        this.target=target;}public void addBook(){    System.out.println("==========添加操作之前=========");            this.target.add();    System.out.println("==========添加操作之后=========");}              }

    然后就是测试了:
<pre name="code" class="java"><span style="font-size:18px;"> package test.proxy;    public class Main{        BookFacade target=new BookFacadeImpl();BookFacadeProxy proxy=new BookFacadeProxy(target);proxy.addBook();}    }</span>



执行测试之后的结果是:


    ==========添加操作之前=========
    添加操作
    ==========添加操作之后=========




    好了,这就是静态代理的一个基本应用。

   接下来就是讲JDK的动态代理技术了。
      动态代理技术主要是利用java.lang.reflect这个包的InvocationHandler接口和Proxy这两个类
  先通过一个例子来演示动态代理的用法和效果
     先定义一个接口:
 package dynamic.proxy;    /**  * 目标对象实现的接口,用JDK来生成代理对象一定要实现一个接口  * @author zyb  * @since 2012-8-9  *  */  public interface UserService {        /**      * 目标方法       */      public abstract void add();    }  

         然后就是实现类:
package dynamic.proxy;     /**  * 目标对象  * @author zyb  * @since 2012-8-9  *  */  public class UserServiceImpl implements UserService {        /* (non-Javadoc)      * @see dynamic.proxy.UserService#add()      */      public void add() {  System.out.println("--------------------add---------------");      }  }  

        接下来就是定义一个代理类:
package dynamic.proxy; import java.lang.reflect.InvocationHandler;  import java.lang.reflect.Method;  import java.lang.reflect.Proxy; public class MyProxy implements InvocationHandler{     //目标对象的引用     private UserService target;     //构造方法传进一个UserService的实现类引用     public MyProxy(UserService target){         this.target=target;     }     //取得代理对象     public Object getMyProxy(){         return Proxy.newProxyInstance(this.target.getClass().getClassLoader(),        this.target.getClass().getInterfaces(),this);     }     @Override     /*        proxy:代理类对象method:就是在这个参数所表示的方法的位置增强,和AOP思想中的横切点很相似(个人理解),         通过反射执行这个方法args:method执行所需要的参数。     */     public Object invoke(Object proxy,Method method,Object[] args) throws Exception{         //用于封装返回结果 Object result; System.out.println("======执行add方法之前============");                 result = method.invoke(target,args); System.out.println("======执行add方法之后============"); return result;     }    }

       然后就是测试了:
package dynamic.proxy;public class Main{public static void main(String[] args) throws Exception{//先声明一个目标对象    UserService target=new UserServiceImpl();            //取得代理对象    UserService proxy = (UserService)new MyProxy(target).getMyProxy();    //使用代理对象执行添加操作    proxy.add();}    }

         输出结果如下:
======执行add方法之前============
        --------------------add---------------
======执行add方法之后============



     好了,通过上面的例子可以知道动态代理对目标对象的add方法进行了增强操作。
   但是从上面的例子也可以看出动态代理的局限性:需要和一个接口绑定在一起,只能针对
   一类接口增强
     其实可以将这个例子理解为一个简单的AOP实现。
   值得注意的是proxy并没有显示的执行MyProxy类的invoke()方法。但是达到了增强操作。
   了解下它背后进行的操作有助于我们更加好的动态代理技术,更好的运用它。


   现在通过代码来探究这个过程:
   将测试类Main改变下:
package dynamic.proxy;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class Main{public static void main(String[] args) throws Exception{//制定被代理的对象UserService target=new UserServiceImpl();//取得代理对象UserService proxy=(UserService) new MyProxy(target).getMyProxy();            //根据这里可以判断proxy是Proxy的子类,同时实现了UserService接口System.out.println(proxy instanceof Proxy);System.out.println(proxy instanceof UserService);System.out.println("==================================");//这里打印出这样的结果:proxy的类型是: class com.sun.proxy.$Proxy0    System.out.println("proxy的类型是: "+proxy.getClass().toString());    System.out.println("===================================");        //这里通过反射技术取得proxy这个对象的信息来分析下proxy的结构    Class clazz=proxy.getClass();        //属性    Field[] fields=clazz.getDeclaredFields();    System.out.println("proxy对象的属性有:");    for(Field f:fields){    System.out.println(f.getName()+" , ");    }    System.out.println("==================================");        //方法    Method[] method=clazz.getMethods();    System.out.println("proxy对象的方法有: ");    for(Method m:method){    System.out.println(m.getName()+" , ");    }    System.out.println("===================================");        //父类    System.out.println("proxy的父类: "+clazz.getSuperclass());    System.out.println("====================================");        //接口    Class<?> interfaces[]=clazz.getInterfaces();    System.out.println("proxy实现的接口有: ");    for(Class<?> i:interfaces){    System.out.println(i.getName()+" , ");    }    System.out.println("====================================");        //运行结果    System.out.println("运行结果: ");    proxy.add();    }    }

接下来是控制台输出的结果:
true
true
==================================
proxy的类型是: class com.sun.proxy.$Proxy0
===================================
proxy对象的属性有:
m1 , 
m3 , 
m0 , 
m2 , 
==================================
proxy对象的方法有: 
add , 
equals , 
toString , 
hashCode , 
isProxyClass , 
getInvocationHandler , 
getProxyClass , 
newProxyInstance , 
wait , 
wait , 
wait , 
getClass , 
notify , 
notifyAll , 
===================================
proxy的父类: class java.lang.reflect.Proxy
====================================
proxy实现的接口有: 
dynamic.proxy.UserService , 
====================================
运行结果: 
======执行add方法之前============
--------------------add---------------
======执行add方法之后============

   
 从上面的输出结果我们可以得出下面的结论:


  1、proxy这个对象所对应的那个类的定义如下:
        public class $Proxy0 extends Proxy implements Uservice{
    //...............
}
  
  2、$Proxy0这个类并没有保存在我们的磁盘中。这个类是java虚拟机在执行代码
     期间根据需求动态创建出来的。java虚拟机创建$Proxy0这个类是直接生成字
     节码文件并且执行$Proxy0的对象proxy的相关方法来“隐式”执行了“增强操作”。


 分析到这里,可能还是会对动态代理的“隐式”执行操作是怎样进行的理解的不够清楚。
  接下来的第二篇来通过分析Proxy这个类和$Proxy0这个类的大概的源码来进一步讲解。
从更底层来理解jdk动态代理技术的实现。



































































0 0
原创粉丝点击