代理模式
代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活 中常见的中介。
- 通过引入代理对象的方式来间接访问目标对象,防止直接访问目标对象给系统带来的不必要复杂性
- 通过代理对象对访问进行控制
代理模式一般会有三个角色:
代理
抽象角色:指代理角色和真实角色对外提供的公共方法,一般为一个接口
真实角色:需要实现抽象角色接口,定义了真实角色所要实现的业务逻辑,以便供代理角色调用。也就是真正的业 务逻辑在此。
代理角色:需要实现抽象角色接口,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附 加自己的操作。将统一的流程控制都放到代理角色中处理!
静态代理
静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类。一般 来说,被代理对象和代理对象是一对一的关系,当然一个代理对象对应多个被代理对象也是可以的。
/**
*抽象 代理角色: 定义了服务的接口
*/
public interface FindHouse {
//找房服务
void findHouseService();
}
/**
* 代理对象:中介平台
*/
public class Agent implements FindHouse {
private final FindHouse findHouse;
public Agent(FindHouse findHouse) {
this.findHouse = findHouse;
}
//....前置处理
public void before() {
System.out.println("创建订单,找到空闲的中介");
}
//....后置处理
public void after() {
System.out.println("满意度调查");
}
@Override
public void findHouseService() {
before();
findHouse.findHouseService();
after();
}
}
/**
* 真实实现类: 中介小李
*/
public class XiaoLi implements FindHouse {
@Override
public void findHouseService() {
System.out.println("我是小李,我帮忙找到了一个100万元的别墅");
}
}
/**
* 实实现类:中介小王
*/
public class XiaoWang implements FindHouse {
@Override
public void findHouseService() {
System.out.println("我是小王,我找到了一个地铁口的200万的复式");
}
}
public static void main(String[] args) throws Exception {
//静态代理
XiaoWang xiaoWang = new XiaoWang();
XiaoLi xiaoLi = new XiaoLi();
//代理平台分配小李帮忙找房
Agent agent = new Agent(xiaoLi);
agent.findHouseService();
//代理平台分配小王帮忙找房
agent.setFindHouse(xiaoWang);
agent.findHouseService();
···
运行代码
image.png
动态代理
静态代理,一对一则会出现时静态代理对象量多、代码量大,从而导致代码复杂,可维护性差的问题,一对多则代 理对象会出现扩展能力差的问题。
如果小王不仅会做房屋中介,还会洗车。
/**
* 洗车能力
*/
public interface WashCar {
void wash();
}
/**
* 实实现类:中介小王,也会洗车
*/
public class XiaoWang implements FindHouse, WashCar {
@Override
public void findHouseService() {
System.out.println("我是小王,我找到了一个地铁口的200万的复式");
}
@Override
public void wash() {
System.out.println("我是小王,我可以洗车");
}
}
在一对一代理情况下,需要再创建一个洗车代理类
public class WashCarAgent implements WashCar {
private WashCar washCar;
public WashCarAgent(WashCar washCar) {
this.washCar = washCar;
}
@Override
public void wash() {
}
}
一对多代理情况下,每增加一个功能就需要修改代理类增加一个变量,造成扩展性差
/**
* 代理对象:中介平台
*/
public class Agent implements FindHouse,WashCar {
private FindHouse findHouse;
private WashCar washCar;//增加一个功能就需要修改代理类,来增加一个变量
public Agent(FindHouse findHouse) {
this.findHouse = findHouse;
}
public void setWashCar(WashCar washCar) {
this.washCar = washCar;
}
@Override
public void wash() {
before();
washCar.wash();
after();
}
}
JDK中为我们提供了生成动态代理类的方法
//动态代理,JDK实现只能代理接口
Object o = Proxy.newProxyInstance(MyClass.class.getClassLoader(),
new Class[]{FindHouse.class,WashCar.class}, new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
return method.invoke(xiaoWang,objects);//传入小王
}
});
FindHouse findHouse = (FindHouse) o;//将生成的代理对象强转为抽象接口
findHouse.findHouseService();//调用方法
WashCar wash = (WashCar) o;
wash.wash();
运行代码
如果传入的是小李,运行代码
实际上, Proxy.newProxyInstance 会创建一个Class,与静态代理不同,这个Class不是由具体的.java源文件编译 而来,即没有真正的文件,只是在内存中按照Class格式生成了一个Class。
String name = Api.class.getName()+"$Proxy0";
//生成代理指定接口的Class数据
byte[] bytes = ProxyGenerator.generateProxyClass(name, new Class[]{FindHouse.class,WashCar.class});
FileOutputStream fos = new FileOutputStream("lib/" + name+".class"); fos.write(bytes);
fos.close();
从内存中导出生成的Class
//生成Class的代码
public final class FindHouse$Proxy0 extends Proxy implements FindHouse, WashCar {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m4;
private static Method m0;
public FindHouse$Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void findHouseService() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void wash() throws {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.enjoy.lib.FindHouse").getMethod("findHouseService");
m4 = Class.forName("com.enjoy.lib.WashCar").getMethod("wash");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
当我们调用这个动态代理对象的findHouseService方法时,我们可以发现,实际调用了
super.h.invoke(this, m3, (Object[])null);
其中的h我们看源码可以看到
public class Proxy implements Serializable {
private static final Class<?>[] constructorParams = new Class[]{InvocationHandler.class};
private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache(new Proxy.KeyFactory(), new Proxy.ProxyClassFactory());
protected InvocationHandler h;//就是我们在动态代理传入的InvocationHandler
private static final Object key0 = new Object();
private Proxy() {
}
protected Proxy(InvocationHandler var1) {
Objects.requireNonNull(var1);
this.h = var1;
}
其中的m3可以看到,就是我们抽象接口定义的方法
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.enjoy.lib.FindHouse").getMethod("findHouseService");
m4 = Class.forName("com.enjoy.lib.WashCar").getMethod("wash");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
网友评论