黑马程序员_动态代理

来源:互联网 发布:皂基洗面奶知乎 编辑:程序博客网 时间:2024/06/05 16:57
-------------Android培训、java培训、期待与您交流!-------------

        代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。

                                                                                              

例如,我们要创建一个任务接口,以便后来的任务去实现

public interface Task {public void dealTask(String taskName); }

实现的接口,也就是委托类

public class RealTask implements Task {@Overridepublic void dealTask(String taskName) {System.out.println("开始执行.............");try {Thread.sleep(100);//让执行线程睡一段时间,代表正在执行任务} catch (InterruptedException e) {e.printStackTrace();}}}
我们不想直接对这个类进行直接访问,或者是对这个类中的一些方法中进行一些附加的功能,如,对这个方法的计算时间做出运算,

public class ProxyTask implements Task {private Task task;@Overridepublic void dealTask(String taskName) {long beginTime = System.currentTimeMillis();//计算当期时间,附加执行任务耗费多长时间task.dealTask(taskName);long endTime = System.currentTimeMillis();System.out.println("执行时长" + (endTime - beginTime));}public ProxyTask(RealTask task) {this.task = task;}}

        由此我们可以看出,我们要去完成这个静态代理,需要我们去实现同一个接口, 如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法,增加了代码维护的复杂度。再有代理对象的一个接口只服务于一种类型的对象,一旦要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。

于是,我们再来看看动态代理。

动态代理技术:
        1、JVM可以在运行期动态生成类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。
        2、JVM生成的动态类必须实现一个或多个接口,所以JVM生成的动态类只能用作具有相同接口的目标类的代理。
        3、CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理类,那么可以使用CGLIB库。

Proxy的一些静态方法:

        1、static InvocationHandler getInvocationHandler(Object proxy) ;获取指定代理对象所关联的调用处理器;
        2、static Class getProxyClass(ClassLoader loader, Class[] interfaces);获取关联于指定类装载器和一组接口的动态代理类的类对象;
        3、static boolean isProxyClass(Class cl) ;判断指定类对象是否是一个动态代理类;
        4、static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h);为指定类装载器、一组接口及调用处理器生成动态代理类实例

       InvocationHandler:调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。其核心方法,该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例,第二个参数是被调用的方法对象,第三个方法是调用参数。

Object invoke(Object proxy, Method method, Object[] args

实现步骤:

       1、实现InvocationHandler接口;

       2、给Proxy类提供类加载器和代理接口类型数组创建动态代理类;

       3、以调用处理器类型为参数,利用反射机制得到动态代理类的构造函数 ;
       4、 利用动态代理类的构造函数创建动态代理类对象 。

       而Proxy类的静态方法newProxyInstance对上面具体步骤的后三步做了封装,简化了动态代理对象的获取过程。 因此,我们只要实现InvocationHandler接口。如,

InvocationHandler handler = new RealProxy(task);//RealProxy是已实现InvocationHandler接口的类Task proxy =  (Task)Proxy.newProxyInstance(task.getClass().getClassLoader(), task.getClass().getInterfaces(),handler);
像这样,我们便能得到所要的代理类。因而,我们在把上面处理Task的例子用动态代理来试下。

首先是实现InvocationHandler接口,

public class RealProxy implements InvocationHandler{Object obj;@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {long beginTime = System.currentTimeMillis();method.invoke(obj,args);//代理对象、代理对象的方法,以及参数可以在其前后或者catch块中都附加系统功能代码long endTime = System.currentTimeMillis();System.out.println("任务执行时长"+(endTime - beginTime));return null;}public RealProxy(Object obj) {this.obj = obj;}}
再创建个生成代理类的功能,传入Task的类加载器、接口数组以及实现了InvocationHandler的类

public static Task getProxy() {Task task = new RealTask();InvocationHandler handler = new RealProxy(task);Task proxy =  (Task)Proxy.newProxyInstance(task.getClass().getClassLoader(), task.getClass().getInterfaces(),handler);return proxy;}}
这样,我们便能得到一个Task的代理类。即使Task接口中有不止一个方法,也不用再去每个方法都进行复写。

这里,InvocationHandler接口自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。

invoke方法涉及的三个要素:
       1、代理对象
       2、方法;
       3、参数。

        Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类。以上仅以两个例子来表达我对动态代理的理解,该思考的还有很多,比如对于无参方法的调用,以及代理对象的接口中没有的方法是否可行,我都会一一进行试验和研究,希望能有更大的收获。




0 0
原创粉丝点击