黑马程序员--动态代理

来源:互联网 发布:可用的数据接口 编辑:程序博客网 时间:2024/05/16 15:57
-------------------- Android培训、java培训、期待与您交流! ----------------------

什么是动态代理疑问
     A接口有C方法,类B实现A接口,原本应该是执行B类中的C方法,可现在不这样做;现在声明产生B类的代理类B1,有它来冒充B类的“兄弟”并“实现”A接口。对外界来说B1应该也有C方法,可当真正调用它的时候,它会去执行与它关联InvocationHandler的invoke()方法,在这个方法里面你可以做很多事情。这样,这个请求就被“代理”到其它地方去了。

代理模式:
    代理模式是常用的Java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。

反射与动态代理
     动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java反射机制可以生成任意类型的动态代理类。Java.lang.reflect包中的Proxy类和InvocationHandler接口提供了生成动态代理类的能力。

反射与动态代理中包含一个类和一个接口:

InvocationHandler接口:public interface InvocationHandler{public Object invoke(Object proxy,Method method,Object[] arge)throws Throwable;}
参数说明:
    Object proxy:只被代理的对象。
    Method method:要调用的方法
    Object[] args:方法调用时所需要的参数。

Proxy类:
    Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:
public static Object newProxyInstance(ClassLoadr loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException
参数说明:
    ClassLoader loader:类加载器
    Class<?>[] interface:得到全部的接口

    InvocationHandler h:得到InvocationHandler接口的子类实例


如图:这张图很精辟的描述了动态代理的工作原理。当客户端调用代理类代理类的构造方法接收一个InvocationHandler的对象,接着客户端调用代理类的各个方法,各个方法会把代理的调用请求转发给刚才通过构造方法传进去的InvocationHandler对象,那么InvocationHandler对象就会把请求分发给目标的相应方法。

下面通过代码实例来证明动态代理的强大功能。

<创建的接口类>

package com.xy.studyproxytest;public interface Hello {     void hello(String name);}
<创建的被代理类>

package com.xy.studyproxytest;public class HelloSpeaker implements Hello {    @Override    public void hello(String name) {        System.out.printf("哈喽,%s%n",name);    }}
<创建的代理类>
package com.xy.studyproxytest;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.logging.Level;import java.util.logging.Logger;public class LoggingHandler implements InvocationHandler {    private Object target;    public Object bind(Object target){        this.target = target;        //动态建立代理对象。        return Proxy.newProxyInstance(target.getClass().getClassLoader(),                target.getClass().getInterfaces(),                this                );    }//代理对象被调用会实现此方法。    @Override    public Object invoke(Object proxy, Method method, Object[] args)            throws Throwable {        Object result = null;        log(String.format("%s() 调用开始。。。", method.getName()));        result = method.invoke(target, args);//实现被代理对象的职责。        log(String.format("%s() 调用结束。。。", method.getName()));        return result;    }    private void log(String message) {        Logger.getLogger(LoggingHandler.class.getName()).log(Level.INFO,message);    }}
<执行类>

package com.xy.studyproxytest;public class ProxyDemo {/** *执行类 */public static void main(String[] args) {LoggingHandler loggingHandler = new LoggingHandler();Hello helloProxy = (Hello) loggingHandler.bind(new HelloSpeaker());helloProxy.hello("xuyan");}}
<执行结果>

2014-5-8 12:09:17 com.xy.studyproxytest.LoggingHandler log信息: 我被黑马录取啦!!!hello() 调用开始。。。2014-5-8 12:09:17 com.xy.studyproxytest.LoggingHandler log信息: 我从黑马毕业上班啦!!!hello() 调用结束。。。哈喽,xuyan
【总结】主要是使用Proxy.newProxyInstance()方法建立代理对象,调用时必须指定类加载器,告知要代理的接口,以及接口上定义方法被调用时的处理者(InvocationHandler实例)。Proxy.new ProxyInstance()方法底层会使用原生方法生成代理对象的Class实例,并利用它来生成代理对象,代理对象会操作指定要代理的接口。如果操作Proxy.newProxyInstance()返回的代理对象,在每次操作时会调用处理器(InvocationHandler实例)的invoke()方法,并传入代理对象、被调用方法的Method实例与参数值。可以在invoke()方法中实现日志,利用被代理对象、被调用的方法Method实例与参数值实现被代理对象的职责。

-------------------- Android培训、java培训、期待与您交流! ----------------------详细请查看:www.itheima.com
0 0