黑马程序员_Java动态代理

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

 

Blog14_1分析代理类的作用

(1)    动态代理类

动态代理类:在运行时能动态的生成一个实现了指定接口的类。

注意事项:动态代理中的实现并不是真正的实现。真正实现接口还得写一个类,而这个类产生的对象,我们叫做“目标对象”。

(2)    动态代理的作用

作用:使得我们在使用目标类的同时能增加附属的功能。

例子:别人提供一个加密的class文件给我们,我们想在调用它其中的任何方法时都能附加上我们自己特有的东西,这时就可以使用动态代理了。

Blog14_2  JVM动态生成类

(3)    创建一个实现Collection接口的动态类

使用Proxy类的getProxyClass()方法可以获取实现一个接口的动态类,如下:

Class clazz=Proxy.getProxyClass(null,Collection.class);

(4)    写代码获取此动态类的所有方法和此类的构造方法

Constructor[] constructors = clazz.getConstructors();
      System.out.println("-------------------构造方法列表----------------");
      for (Constructor constructor : constructors) {
         String name = constructor.getName();
         StringBuilder sb = new StringBuilder(name + "(");
         Class[]praraClazz = constructor.getParameterTypes();
         for (Class praraName: praraClazz) {
            sb.append(praraName.getName());
         }
         sb.append(")");
         System.out.println(sb);
      }
      System.out.println("-------------------方法列表----------------");
      Method[]methods = clazz.getMethods();
      for (Method method :methods) {
         String name = method.getName();
         StringBuilder sb = new StringBuilder(name + "(");
         Class[]paraName = method.getParameterTypes();
         for (ClassparaNameClazz : paraName) {
            sb.append(paraNameClazz.getName());
         }
         sb.append(")");
         System.out.println(sb);
      }

输出结果为:

-------------------构造方法列表----------------

com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler)

-------------------方法列表----------------

add(java.lang.Object)

remove(java.lang.Object)

equals(java.lang.Object)

toString()

hashCode()

clear()

contains(java.lang.Object)

isEmpty()

size()

toArray()

toArray([Ljava.lang.Object;)

addAll(java.util.Collection)

iterator()

containsAll(java.util.Collection)

removeAll(java.util.Collection)

retainAll(java.util.Collection)

isProxyClass(java.lang.Class)

getInvocationHandler(java.lang.Object)

getProxyClass(java.lang.ClassLoader[Ljava.lang.Class;)

newProxyInstance(java.lang.ClassLoader[Ljava.lang.Class;java.lang.reflect.InvocationHandler)

wait(longint)

wait(long)

wait()

getClass()

notify()

notifyAll()

---------------------------------------------------------------------------

由上面的输出结果分析可知,生成的动态类,具备了Collection和其父类的所有方法,而且还有一个带参数的构造方法,构造函数的参数为InvocationHandler类型的一个实例对象,查找ApI发现InvocationHandler是一个接口,故传递的对象为此接口的子类实现类的实例对象。

Blog14_3  JVM创建动态类的实例对象

(1)首先使用字节码文件对象,获取构造器对象

由上面的列子我们可知动态类的构造方法为:com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler)

传递的参数为InvocationHandler对象,故获取构造器对象时传递的参数应该是 InvocationHandler.class如下:

Constructor con=clazz.getConstructor(InvocationHandler.class);

(2)然后使用构造器对象调用newInstance创建对象。如下:

   Collection collect=(Collection)con.newInstance(newInvocationHandler );但此时发现InvocationHandler是接口,不能直接创建对象,故我们使用匿名内部类的方法创建接口InvocationHandler的对象。代码如下:  

Constructor con= clazz.getConstructor(InvocationHandler.class);
      Collection collect=(Collection)con.newInstance(new InvocationHandler(){
         ArrayList arr=new ArrayList();
         @Override
         public Object invoke(Objectproxy, Method method, Object[] args)
                throws Throwable {
            Object obj=method.invoke(arr,args);
            return obj;
         }
      });

    上面创建动态类实例对象的过程是:先得到Proxy类的字节码文件对象,利用字节码文件对象得到构造器对象,使用构造器对象调用

newInstance()方法得到代理对象。

(5) 另外一种创建动态类实例对象的简便方法

使Proxy类提供的静态方法:

newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
代码如下:
      Collection coll=(Collection)Proxy.newProxyInstance(null, new Class[]{Collection.class}, new InvocationHandler() {
         ArrayList arr=new ArrayList();
         @Override
         public Object invoke(Objectproxy, Method method, Object[] args)
                throws Throwable {
            System.out.println("增强啦。。。");
            Object obj=method.invoke(arr, args);
            return obj;
         }
      });

此种方法相比第一种方法更简单直接,提倡使用第二种方法。

(6) 使用动态代理对象调用动态类中的方法

如上面例子:

collect.add("动态代理1");

collect.add("动态代理2");

collect.add("动态代理3");

System.out.println(collect);

输出的结果为:

"增强啦。。。"

"增强啦。。。"

"增强啦。。。"

"增强啦。。。"

[动态代理1,动态代理2,动态代理3]

分析可知:每当动态代理对象每调用一次方法,都会先调用invoke方法。并且每次调用方法的返回值实际为invoke方法的返回值。

动态代理中invoke方法注意事项:

A.  每当动态代理对象每调用一次方法,都会先调用invoke方法;

B.  动态代理对象调用方法后返回值均为invoke方法的返回值;

C.  调用的方法实质上是目标对象当中的方法,而不是动态代理类中的(动态代理知识拥有了接口中的抽象方法,而并没有去实现它);

D.  利用A的原理,我们可以再invoke方法中加上附加的功能达到:调用所用的方法时都同时能使用我们自己的附加功能;

E.父类中带有native修饰的方法不会调用invoke方法。

Blog14_4  一个动态代理工厂的实现

需求:封装一个类,让这个类拥有一个创建代理对象的方法,当外界向这个类传递包含:目标对象、增强操作对象、接口的参数时,这个类能自动创建所需的动态代理对象,并且还具有增强的功能。

实现代码实现如下:

public class ProxyFactory {
private ClassLoader loader=ProxyFactory.class.getClassLoader();
   private Class[]interfaces;
   private Object target;
   private Before before;
   private After after;
   public ProxyFactory(Class[]interfaces, Object target, Before before,After after) {
      super();
      this.interfaces = interfaces;
      this.target = target;
      this.before = before;
      this.after = after;
   }
   public Object creatProxy(){
      Objectobj=Proxy.newProxyInstance(
            loader,                       //第一个参数
            interfaces,                  //第二个参数
            new InvocationHandler(){   //第三个参数
                @Override
                public Object invoke(Objectproxy, Method method, Object[] args)
                      throws Throwable {
            before.beforShow();
                //注意:动态代理的目标对象,必须是实现了接口的对象。
            Object resultObj=method.invoke(target, args);
            after.afterShow();
                   //System.out.println(resultObj);
                   return resultObj;
                }
            }
            );
      return obj;
   }

如上面代码:创建这个类的对象,当向构造方法中传递需要实现的接口数组interfaces、实现接口的目标对象target、增强操作的对象Before before,After after。再调用creatProxy()方法就能创建实现这些接口的动态代理对象了。这样当动态代理对象调用接口中所拥有的方法时,还会在invoke的前面或者后面使用我们自己的增强功能。

 

----------------------- android培训java培训、java学习型技术博客、期待与您交流! ----------------------

详情请查看:http://edu.csdn.net/heima


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值