代理模式(英语:Proxy Pattern)是程序设计中的一种设计模式。
代理模式是对其他对象提供一种代理以控制对这个对象的访问。代理模式的思想是为了提供额外的处理或者不同的操作而在实际对象与调用者之间插入一个代理对象。这些额外的操作通常需要与实际对象进行通信。
代理可分为静态代理和动态代理。
代理模式一般涉及到的角色有:
抽象角色:声明真实对象和代理对象的共同接口;
代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。
静态代理实例: 抽象角色
public abstract class Subject { public abstract void request(); }
<span style="color: rgb(255, 0, 0); font-family: Arial;"><span style="color: rgb(255, 0, 0); font-family: Arial; font-size: 14px; line-height: 26px; text-indent: 28px;">真实角色</span></span>
<pre name="code" class="java" style="font-size: 14px; line-height: 26px; text-indent: 28px; color: rgb(51, 51, 51);"><span style="font-family: Arial;">public class RealSubject extends Subject {</span>@Overridepublic void request() {// TODO Auto-generated method stub}}
<span style="font-family: Arial;"></span><pre name="code" class="java" style="font-size: 14px; line-height: 26px; text-indent: 28px;"><span style="color:#ff0000;">代理角色</span>
public class ProxySubject extends Subject { private RealSubject realSubject = null; @Override public void request() { preRequest(); //真实角色操作前的附加操作 if(realSubject == null){ realSubject = new RealSubject(); } realSubject.request(); postRequest(); //真实角色操作后的附加操作 } private void postRequest() { // TODO Auto-generated method stub } private void preRequest() { // TODO Auto-generated method stub } }
public class Main { public static void main(String[] args) { Subject subject = new ProxySubject(); subject.request(); //代理者代替真实者做事情 } }
<span style=" font-family: Arial; background-color: rgb(255, 255, 255);"><strong>动态代理</strong></span>
Java动态代理类位于Java.lang.reflect包下,一般主要涉及到以下两个类:
(1). Interface InvocationHandler:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
proxy
- 在其上调用方法的代理实例
method
- 对应于在代理实例上调用的接口方法的
Method
实例。
Method
对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。
args
- 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为
null
。基本类型的参数被包装在适当基本包装器类(如
java.lang.Integer
或
java.lang.Boolean
)的实例中。
null
并且接口方法的返回类型是基本类型,则代理实例上的方法调用将抛出
NullPointerException
。否则,如果此方法返回的值与上述接口方法的声明返回类型不兼容,则代理实例上的方法调用将抛出
ClassCastException
。
(2).Proxy:该类即为动态代理类,作用类似于上例中的ProxySubject,其中主要包含以下内容:
Protected Proxy(InvocationHandler h):构造函数,
protected Proxy(InvocationHandler h)
Proxy
实例。
h
- 此代理实例的调用处理程序
public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException
java.lang.Class
对象,并向其提供类加载器和接口数组。该代理类将由指定的类加载器定义,并将实现提供的所有接口。如果类加载器已经定义了具有相同排列接口的代理类,那么现有的代理类将被返回;否则,类加载器将动态生成并定义这些接口的代理类。
对可以传递给 Proxy.getProxyClass
的参数有以下几个限制:
interfaces
数组中的所有 Class
对象必须表示接口,而不能表示类或基本类型。 interfaces
数组中的两个元素不能引用同一 Class
对象。 cl
和所有接口 i
,以下表达式必须为 true: Class.forName(i.getName(), false, cl) == i
interfaces
数组的大小必须不超过 65535。 如果违反了这些限制,Proxy.getProxyClass
将抛出 IllegalArgumentException
。如果 interfaces
数组参数或其任何元素为 null
,则将抛出 NullPointerException
。
注意,指定的代理接口的顺序非常重要:对接口组合相同但顺序不同的代理类的两个请求会导致两个不同的代理类。
loader
- 定义代理类的类加载器
interfaces
- 代理类要实现的接口列表
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
Proxy.getProxyClass(loader, interfaces). getConstructor(new Class[] { InvocationHandler.class }). newInstance(new Object[] { handler });
Proxy.newProxyInstance
抛出 IllegalArgumentException
,原因与 Proxy.getProxyClass
相同。
loader
- 定义代理类的类加载器
interfaces
- 代理类要实现的接口列表
h
- 指派方法调用的调用处理程序
动态代理类(以下简称为代理类)是一个实现在创建类时在运行时指定的接口列表的类,该类具有下面描述的行为。 代理接口 是代理类实现的一个接口。 代理实例 是代理类的一个实例。 每个代理实例都有一个关联的调用处理程序 对象,它可以实现接口 InvocationHandler
。通过其中一个代理接口的代理实例上的方法调用将被指派到实例的调用处理程序的 Invoke
方法,并传递代理实例、识别调用方法的 java.lang.reflect.Method
对象以及包含参数的 Object
类型的数组。调用处理程序以适当的方式处理编码的方法调用,并且它返回的结果将作为代理实例上方法调用的结果返回。
与上例类似只修改代理对象:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class DynamicSubject implements InvocationHandler { private Object sub; // 真实对象的引用 public DynamicSubject(Object sub) { this.sub = sub; } @Override 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; } }main():
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class Main { public static void main(String[] args) throws Throwable { RealSubject rs = new RealSubject(); InvocationHandler handler = new DynamicSubject(rs); Class cls = rs.getClass(); Class c = Proxy.getProxyClass(cls.getClassLoader(), cls.getInterfaces()); Constructor ct = c.getConstructor(new Class[]{InvocationHandler.class}); Subject subject =(Subject) ct.newInstance(new Object[]{handler}); subject.request(); } }