java代理模式和动态代理的实现java
一、代理模式数组
代理模式的做用是:为其余对象提供一种代理以控制对这个对象的访问。在某些状况下,一个客户不想或者不能直接引用另外一个对象,而代理对象能够在客户端和目标对象之间起到中介的做用。
代理模式通常涉及到三个角色:
抽象角色:声明真实对象和代理对象的共同接口;
代理角色:代理对象角色内部含有对真实对象的引用,从而能够操做真实对象,同时代理对象提供与真实对象相同的接口以便在任什么时候刻都能代替真实对象。同时,代理对象能够在执行真实对象操做时,附加其余的操做,至关于对真实对象进行封装。
真实角色:代理角色所表明的真实对象,是咱们最终要引用的对象。
如下以《Java与模式》中的示例为例:
抽象角色:
[Java] 纯文本查看 复制代码
?
1
2
3
abstract public class Subject {函数
abstract public void request();
}
真实角色:实现了Subject的request()方法。
[Java] 纯文本查看 复制代码
?post
public class RealSubject extends Subject {代理
public RealSubject() { } public void request() { System.out.println( " From real subject. " ); }
}
代理角色:
[Java] 纯文本查看 复制代码
?code
public class ProxySubject extends Subject {对象
private RealSubject realSubject; // 以真实角色做为代理角色的属性 public ProxySubject() { } public void request() { // 该方法封装了真实对象的request方法 preRequest(); if ( realSubject == null ) { realSubject = new RealSubject(); } realSubject.request(); // 此处执行真实对象的request方法 postRequest(); }
客户端调用:接口
[Java] 纯文本查看 复制代码
?
1
2
Subject sub = new ProxySubject();
Sub.request();get
由以上代码能够看出,客户实际须要调用的是RealSubject类的request()方法,如今用ProxySubject来代理 RealSubject类,一样达到目的,同时还封装了其余方法(preRequest(),postRequest()),能够处理一些其余问题。
另外,若是要按照上述的方法使用代理模式,那么真实角色必须是事先已经存在的,并将其做为代理对象的内部属性。可是实际使用时,一个真实角色必须对应一个 代理角色,若是大量使用会致使类的急剧膨胀;此外,若是事先并不知道真实角色,该如何使用代理呢?这个问题能够经过Java的动态代理类来解决。io
二、动态代理类
Java动态代理类位于Java.lang.reflect包下,通常主要涉及到如下两个类:
(1). Interface InvocationHandler:该接口中仅定义了一个方法Object:invoke(Object obj,Method method, Object[] args)。在实际使用时,第一个参数obj通常是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。 这个抽象方法在代理类中动态实现。
(2).Proxy:该类即为动态代理类,做用相似于上例中的ProxySubject,其中主要包含如下内容:
Protected Proxy(InvocationHandler h):构造函数,估计用于给内部的h赋值。
Static Class getProxyClass (ClassLoader loader, Class[] interfaces):得到一个代理类,其中loader是类装载器,interfaces是真实类所拥有的所有接口的数组。
Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类能够看成被代理类使用(可以使用被代理类的在Subject接口中声明过的方法)。
所谓Dynamic Proxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,而后该class就宣称它实现了这些 interface。你固然能够把该class的实例看成这些interface中的任何一个来用。固然啦,这个Dynamic Proxy其实就是一个Proxy,它不会替你做实质性的工做,在生成它的实例时你必须提供一个handler,由它接管实际的工做。
在使用动态代理类时,咱们必须实现InvocationHandler接口,以第一节中的示例为例:
[Java] 纯文本查看 复制代码
?
抽象角色(以前是抽象类,此处应改成接口):
public interface Subject {
abstract public void request();
}
具体角色RealSubject:
public class RealSubject implements Subject {
public RealSubject() {}
public void request() { System.out.println( " From real subject. " );
}
}
代理处理器:
[Java] 纯文本查看 复制代码
?
import java.lang.reflect.Method;
import java.lang.reflect.InvocationHandler;
public class DynamicSubject implements InvocationHandler {
private Object sub;
public DynamicSubject() {}
public DynamicSubject(Object obj) { sub = obj;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println( " before calling " + method);
method.invoke(sub,args);
System.out.println( " after calling " + method);
return null ;
}
}
该代理类的内部属性为Object类,实际使用时经过该类的构造函数DynamicSubject(Object obj)对其赋值;此外,在该类还实现了invoke方法,该方法中的
method.invoke(sub,args);
其实就是调用被代理对象的将要被执行的方法,方法参数sub是实际的被代理对象,args为执行被代理对象相应操做所需的参数。经过动态代理类,咱们能够在调用以前或以后执行一些相关操做。
客户端:
[Java] 纯文本查看 复制代码
?
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class Client {
static public void main(String[] args) throws Throwable {
RealSubject rs = new RealSubject(); // 在这里指定被代理类
InvocationHandler ds = new DynamicSubject(rs);
Class cls = rs.getClass();
// 如下是一次性生成代理 Subject subject = (Subject) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),ds );
subject.request();
}
程序运行结果:
before calling public abstract void Subject.request()
From real subject.
after calling public abstract void Subject.request()
经过这种方式,被代理的对象(RealSubject)能够在运行时动态改变,须要控制的接口(Subject接口)能够在运行时改变,控制的方式(DynamicSubject类)也能够动态改变,从而实现了很是灵活的动态代理关系。