java动态代理中的invoke方法是如何被自动调用的(一)

2014-11-23 23:56:39 · 作者: · 浏览: 0
一、动态代理与静态代理的区别。 (1)Proxy类的代码被固定下来,不会因为业务的逐渐庞大而庞大; (2)可以实现AOP编程,这是静态代理无法实现的; (3)解耦,如果用在web业务下,可以实现数据层和业务层的分离。 (4)动态代理的优势就是实现无侵入式的代码扩展。 静态代理这个模式本身有个大问题,如果类方法数量越来越多的时候,代理类的代码量是十分庞大的。所以引入动态代理来解决此类问题

二、动态代理

Java中动态代理的实现,关键就是这两个东西:Proxy、InvocationHandler,下面从InvocationHandler接口中的invoke方法入手,简单说明一下Java如何实现动态代理的。
首先,invoke方法的完整形式如下:

Java代码 收藏代码
  1. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
  2. {
  3. method.invoke(obj, args);
  4. return null;
  5. }
    首先猜测一下,method是调用的方法,即需要执行的方法;args是方法的参数;proxy,这个参数是什么?以上invoke()方法的实现即是比较标准的形式,我们看到,这里并没有用到proxy参数。查看JDK文档中Proxy的说明,如下:
    Java代码 收藏代码
    1. A method invocation on a proxy instance through one of its proxy interfaces will be dispatched to the invoke method of the instance's invocation handler, passing the proxy instance,a java.lang.reflect.Method object identifying the method that was invoked, and an array of type Object containing the arguments.
      由此可以知道以上的猜测是正确的,同时也知道,proxy参数传递的即是代理类的实例。

      为了方便说明,这里写一个简单的例子来实现动态代理。

      Java代码 收藏代码
      1. //抽象角色(动态代理只能代理接口)
      2. public interface Subject {
      3. public void request();
      4. }
        Java代码 收藏代码
        1. //真实角色:实现了Subject的request()方法
        2. public class RealSubject implements Subject{
        3. public void request(){
        4. System.out.println("From real subject.");
        5. }
        6. }
          Java代码 收藏代码
          1. //实现了InvocationHandler
          2. public class DynamicSubject implements InvocationHandler
          3. {
          4. private Object obj;//这是动态代理的好处,被封装的对象是Object类型,接受任意类型的对象
          5. public DynamicSubject()
          6. {
          7. }
          8. public DynamicSubject(Object obj)
          9. {
          10. this.obj = obj;
          11. }
          12. //这个方法不是我们显示的去调用
          13. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
          14. {
          15. System.out.println("before calling " + method);
          16. method.invoke(obj, args);
          17. System.out.println("after calling " + method);
          18. return null;
          19. }
          20. }
            Java代码 收藏代码
            1. //客户端:生成代理实例,并调用了request()方法
            2. public class Client {
            3. public static void main(String[] args) throws Throwable{
            4. // TODO Auto-generated method stub
            5. Subject rs=new RealSubject();//这里指定被代理类
            6. InvocationHandler ds=new DynamicSubject(rs);
            7. Class cls=rs.getClass();
            8. //以下是一次性生成代理
            9. Subject subject=(Subject) Proxy.newProxyInstance(
            10. cls.getClassLoader(),cls.getInterfaces(), ds);
            11. //这里可以通过运行结果证明subject是Proxy的一个实例,这个实例实现了Subject接口
            12. System.out.println(subject instanceof Proxy);
            13. //这里可以看出subject的Class类是$Proxy0,这个$Proxy0类继承了Proxy,实现了Subject接口
            14. System.out.println("subject的Class类是:"+subject.getClass().toString());
            15. System.out.print("subject中的属性有:");
            16. Field[] field=subject.getClass().getDeclaredFields();
            17. for(Field f:field){
            18. System.out.print(f.getName()+", ");
            19. }
            20. System.out.print("\n"+"subject中的方法有:");
            21. Method[] method=subject.getClass().getDeclaredMethods();
            22. for(Method m:method){
            23. System.out.print(m.getName()+", ");
            24. }
            25. System.out.println("\n"+"subject的父类是:"+subject.getClass().getSuperclass());
            26. System.out.print("\n"+"subject实现的接口是:");
            27. Class [] interfaces=subject.getClass().getInterfaces();
            28. for(Class i:interfaces){
            29. System.out.print(i.getName()+", ");
            30. }
            31. System.out.println("\n\n"+"运行结果为:");
            32. subject.request();
            33. }
            34. }
              Xml代码 收藏代码
              1. 运行结果如下:此处省略了包名,***代替
              2. true
              3. subject的Class类是:class $Proxy0
              4. subject中的属性有:m1, m3, m0, m2,
              5. subject中的方法有:request, hashCode, equals, toString,
              6. subject的父类是:class java.lang.reflect.Proxy
              7. subject实现的接口是:cn.edu.ustc.dynamicproxy.Subject,
              8. 运行结果为:
              9. before calling public ab