一、概念
代理模式(Proxy Pattern)是指为其他对象提供一种代理,以控制对这个对象的访问,属于结构型 模式。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标 对象之间起到中介的作用。
二、分类
代理分为静态代理和动态代理。
静态代理
例子:
有一些闲置的物品需要放在一些平台进行代售,本文根据这个案例模拟静态设计模式。
public interface ITicket {
void sellTicket();
}
public class SellUser implements ITicket{
@Override
public void sellTicket() {
System.out.println("闲置物品");
}
}
public class PlatFormProxy implements ITicket{
private ITicket ticket;
public PlatFormProxy(ITicket ticket){
this.ticket = ticket;
}
@Override
public void sellTicket() {
System.out.println("xx平台出售物品如下");
ticket.sellTicket();
}
}
public class Client {
public static void main(String[] args) {
SellUser sellUser = new SellUser();
PlatFormProxy platFormProxy = new PlatFormProxy(sellUser);
platFormProxy.sellTicket();
}
}
动态代理
从静态代理的代码中可以发现,静态代理的缺点显而易见,那就是当真实类的方法越来越多的时候,这样构建的代理类的代码量是非常大的,所以就引进动态代理.动态代理允许使用一种方法的单个类(代理类)为具有任意数量方法的任意类(真实类)的多个方法调用提供服务,看到这句话,可以容易的联想到动态代理的实现与反射密不可分。
Jdk代理涉及到java.lang.reflect包中的InvocationHandler接口和Proxy类,核心方法是
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
jdk动态代理过程中实际上代理的是接口,是因为在创建代理实例的时候,依赖的是java.lang.reflect包中Proxy类的newProxyInstance方法,该方法的生效就恰恰需要这个参数;
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException{
……
}
我们就以房东出租房子作为例子模拟动态代理
public interface Rent {
public void rent();
}
public class Host implements Rent{
@Override
public void rent() {
System.out.println("房东出租屋子");
}
}
public class ProxyInvocationHandler implements InvocationHandler {
private Rent rent;
public void setRent(Rent rent){
this.rent = rent;
}
public Object getProxy(){
Object o = Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
return o;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理本质就是使用反射
seeHouse();
Object invoke = method.invoke(rent, args);
return invoke;
}
public void seeHouse(){
System.out.println("中介带你看房子");
}
}
public class Client {
public static void main(String[] args) {
Host host = new Host();//代理角色
//代理角色
ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();
proxyInvocationHandler.setRent(host);
Rent proxy = (Rent) proxyInvocationHandler.getProxy();
proxy.rent();
}
}
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
//检查InvocationHandler是否为空,为空抛出空指针异常
Objects.requireNonNull(h);
//克隆拿到接口
final Class<?>[] intfs = interfaces.clone();
//进行安全校验
final SecurityManager sm = System.getSecurityManager();
//检查是否能被代理
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
* 得到代理类
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
//通过构造方法得到代理类的对象
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
//new得到代理对象
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
概况的说,上面通过反射获取代理类的构造器生成代理类对象。
为什么会自动执行里面的invoke方法呢?
//以下代码由$Proxy0.class反编译得到
public final class $Proxy0 extends Proxy implements PorxyInte {
private static Method m3;
static {
m3 = Class.forName("cn.itcast.web.Test.PorxyInte").getMethod("test", new Class[0]);
}
//构造方法。将invocationhandler实例从代理类赋值到父类
public $Proxy0(InvocationHandler invocationhandler)
{
super(invocationhandler);//创建父类对象
}
//此处可以看出,当调用代理类的test方法,会执行父类对象属性h的invoke方法,
//h即为通过匿名内部类创建的处理器对象
public final void test() {
super.h.invoke(this, m3, null); //这里的this是代理对象,m3为test方法
}
参考: