代理是一种经常使用的设计模式,其目的就是为其余对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。html
代理模式UML图:java
简单结构示意图:设计模式
为了保持行为的一致性,代理类和委托类一般会实现相同的接口,因此在访问者看来二者没有丝毫的区别。经过代理类这中间一层,能有效控制对委托类对象的直接访问,也能够很好地隐藏和保护委托类对象,同时也为实施不一样控制策略预留了空间,从而在设计上得到了更大的灵活性。Java 动态代理机制以巧妙的方式近乎完美地实践了代理模式的设计理念。数组
Java动态代理类位于java.lang.reflect包下,通常主要涉及到如下两个类:函数
(1)Interface InvocationHandler:该接口中仅定义了一个方法this
在实际使用时,第一个参数obj通常是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。这个抽象方法在代理类中动态实现。spa
(2)Proxy:该类即为动态代理类,其中主要包含如下内容:设计
protected Proxy(InvocationHandler h):构造函数,用于给内部的h赋值。代理
static Class getProxyClass (ClassLoaderloader, Class[] interfaces):得到一个代理类,其中loader是类装载器,interfaces是真实类所拥有的所有接口的数组。code
static Object newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类能够看成被代理类使用(可以使用被代理类的在Subject接口中声明过的方法)
所谓DynamicProxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,而后该class就宣称它实现了这些 interface。你固然能够把该class的实例看成这些interface中的任何一个来用。固然,这个DynamicProxy其实就是一个Proxy,它不会替你做实质性的工做,在生成它的实例时你必须提供一个handler,由它接管实际的工做。
在使用动态代理类时,咱们必须实现InvocationHandler接口
经过这种方式,被代理的对象(RealSubject)能够在运行时动态改变,须要控制的接口(Subject接口)能够在运行时改变,控制的方式(DynamicSubject类)也能够动态改变,从而实现了很是灵活的动态代理关系。
动态代理步骤:
1.建立一个实现接口InvocationHandler的类,它必须实现invoke方法
2.建立被代理的类以及接口
3.经过Proxy的静态方法
newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)建立一个代理
4.经过代理调用方法
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 实际对象 */ class RealSubject implements Subject { /** * 你好 * * @param name * @return */ public String SayHello(String name) { return "hello " + name; } /** * 再见 * * @return */ public String SayGoodBye() { return " good bye "; } } /** * 调用处理器实现类 * 每次生成动态代理类对象时都须要指定一个实现了该接口的调用处理器对象 */ class InvocationHandlerImpl implements InvocationHandler { /** * 这个就是咱们要代理的真实对象 */ private Object subject; /** * 构造方法,给咱们要代理的真实对象赋初值 * * @param subject */ public InvocationHandlerImpl(Object subject) { this.subject = subject; } /** * 该方法负责集中处理动态代理类上的全部方法调用。 * 调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行 * * @param proxy 代理类实例 * @param method 被调用的方法对象 * @param args 调用参数 * @return * @throws Throwable */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //在代理真实对象前咱们能够添加一些本身的操做 System.out.println("在调用以前,我要干点啥呢?"); System.out.println("Method:" + method); //当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用 Object returnValue = method.invoke(subject, args); //在代理真实对象后咱们也能够添加一些本身的操做 System.out.println("在调用以后,我要干点啥呢?"); return returnValue; } } /** * 动态代理演示 */ public class ProxyTest { public static void main(String[] args) { //代理的真实对象 Subject realSubject = new RealSubject(); /** * InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发 * 其内部一般包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用. * 即:要代理哪一个真实对象,就将该对象传进去,最后是经过该真实对象来调用其方法 */ InvocationHandler handler = new InvocationHandlerImpl(realSubject); ClassLoader loader = realSubject.getClass().getClassLoader(); Class[] interfaces = realSubject.getClass().getInterfaces(); /** * 该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例 */ Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler); System.out.println("动态代理对象的类型:"+subject.getClass().getName()); String hello = subject.SayGoodBye(); System.out.println(hello); // String goodbye = subject.SayGoodBye(); // System.out.println(goodbye); } }