现在的位置: 首页 > 综合 > 正文

黑马程序员__动态代理

2014年01月19日 ⁄ 综合 ⁄ 共 3735字 ⁄ 字号 评论关闭

----------------------android培训java培训、期待与您交流!
-------------------------------------

 

动态代理(Proxy)概述:
 JDK的动态代理,实际上就是“反射”与“执行时动态生成字节码”二者的结合体。代理模式的主要作用是为其他对象提供一种代理以控制对这个对象的访问。(代理对象内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装)

Proxy运行原理:
客户端调用代理,代理的构造方法接受一个Handler,客户端调用代理的各个方法,代理各个方法将调用请求转给handler对象的invoke方法(可以添加新的方法),handler将对应请求分发给对应目标的相应请求。把需要的功能封装成对象,即把切面中的代码封装成对象,以对象的形式传递给切面内部,切面内部执行对象就等于执行了切面内的代码。

 

使用条件:JVM生成的动态类必须实现一个或多个接口,所以JVM生成的动态类只能用作具有相同接口的目标类和代理。(生成的动态类就具有接口中的方法)   PS:CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以如果要为一个没有实现接口的类生成动态代理类,那么可以使用CGLIB库。(根据接口有无选择)

代理类的各个方法中通常除了要调用目标(target)和相应方法对外返回目标返回结果外,还可以在代理方法中的如下四个位置加上系统功能代码:
 1、在调用目标方法之前2、在调用目标方法之后3、在调用目标方法前后4、在处理目标方法异常的catch块中

Proxy中方法:
static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)
          返回代理类的 java.lang.Class 对象,并向其提供类加载器和接口数组。
 String getName()
          以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。
static Object .newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
          返回一个指定接口的代理类实例,返回后的代理类可以当作被代理类使用,该接口可以将方法调用指派到指定的调用处理程序。
三个参数:
ClassLoader loader    ----指定被代理对象的类加载器
Class[] Interfaces    ----指定被代理对象所实现的接口
InvocationHandler h  ----指定需要调用的InvocationHandler对象

java.lang.reflect.InvocationHandler,
InvocationHandler 是代理实例的调用处理程序 实现的接口。//InvocationHandler;调用 处理程序
invoke() 在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。

---------------------
import java.lang.reflect.Proxy; 
import java.lang.reflect.*; 
import java.util.*; 
class ProxyTest 

    public static void main(String[] args)throws Exception 
    { 
        Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(),Collection.class); 

 //getProxyClass(ClassLoader loader, Class<?>... interfaces)  返回代理类的 Class 对象,并向其提供类加载器和接口数组。

        System.out.println(clazzProxy1.getName()); //Class 中  .getName()返回此对象所表示的类或接口名。
        Constructor[] constructors = clazzProxy1.getConstructors();  //某类字节码的实例对象调用.getConstructor(),返回其构造器集合
        for (Constructor constructor : constructors) 
        { 
            String name = constructor.getName(); 
            StringBuilder sb = new StringBuilder(name);  //ild和ff大致类似,ff同步,ild单线程效率高
            sb.append('('); 
            Class[] clazzParams = constructor.getParameterTypes();
 // Class<?>[] .getParameterTypes() 按照声明顺序返回一组 Class 对象,这些对象表示此Constructor对象所表示构造方法的形参类型。

            for (Class clazzParam : clazzParams)  
            { 
                String name1 = clazzParam.getName();//返回每个含参构造器的类
                sb.append(name1).append(','); 
            } 
            if(clazzParams != null && clazzParams.length != 0)  //判断是否有构造器
            { 
                sb.deleteCharAt(sb.length()-1); 
            } 
            sb.append(')'); 
            System.out.println(sb.toString()); 
 
        }  
----    
 Collection proxy2 = (Collection)constructor.newInstance(new InvocationHandler(){ //用匿名内部类创建构造函数
   //  invokes三要素:代理对象,代理方法,方法接收的参数
  public Object invoke(Object proxy, Method method, Object[] args)
     throws Throwable {
   return null;
  }
   
 });
}
---------------
JDK中具体的动态代理类是怎么产生的呢?

1.产生代理类$Proxy0类

执行了Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)

将产生$Proxy0类,它继承Proxy对象,并根据第二个参数,实现了被代理类的所有接口,自然就可以生成接口要实现的所有方法了(这时候会重写hashcode,toString和equals三个方法),但是还没有具体的实现体;

2.    将代理类$Proxy0类加载到JVM中

这时候是根据Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)它的第一个参数----就是被代理类的类加载器,把当前的代理类加载到JVM中

3.    创建代理类$Proxy0类的对象

调用的$Proxy0类的$Proxy0(InvocationHandler)构造函数,生成$Proxy0类的对象

参数就是Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)它的第三个参数

这个参数就是我们自己实现的InvocationHandler对象,我们知道InvocationHandler对象中组合加入了代理类代理的接口类的实现类;所以,$Proxy0对象调用所有要实现的接口的方法,都会调用InvocationHandler对象的invoke()方法实现;

4.    生成代理类的class byte

动态代理生成的都是二进制class字节码

 

----------android培训java培训、期待与您交流!
----------------------详细请查看:
http://edu.csdn.net/heima(日记必用代码)

抱歉!评论已关闭.