之前的两篇文章《Java反射——Proxy和动态代理》、《CGLIB动态代理原理分析》,介绍了代理模式,引出动态代理。然后分别介绍了常用的JDK动态代理和CGLIB动态代理。本篇再次回顾下关键点。
1.代理模式
先上类图
- 控制对象访问
- 代理类和被代理类都实现了同一接口,代理类持有被代理类的引用。
静态代理十分简单易懂,但随着被代理对象的增加,代理类也会随之增加。但每个代理类所做的工作又十分类似。为了解决这一问题,引出了动态代理。
动态代理
如上所述,抽象出了公共的代理类。在运行时,动态生成具体的代理类。
JDK动态代理,引入Proxy类来生成代理类。真正的代理类为$Proxy0。
Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),targetObject.getClass().getInterfaces(),this);
工具类Proxy,根据传入的目标类的信息,生成代理类$Proxy0。
举例说明:
被代理类:AgencyServiceImpl
共同实现接口:AgencyService
代理类:$Proxy0
保存生成的代理类Class文件
FileOutputStream out = null;
try {
byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", AgencyServiceImpl.class.getInterfaces());
out = new FileOutputStream(filePath[0] + "$Proxy0.class");
out.write(classFile);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.flush();
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
$Proxy0
public final class $Proxy0 extends Proxy implements AgencyService {
private static Method m1;
private static Method m4;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m4 = Class.forName("com.family.service.AgencyService").getMethod("queryAgency", Class.forName("com.family.model.AgencyInfo"));
m3 = Class.forName("com.family.service.AgencyService").getMethod("test");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
public final List queryAgency(AgencyInfo var1) throws {
try {
return (List)super.h.invoke(this, m4, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
......
}
对应完整类图如下:
CGLIB动态代理类似,生成的$Proxy0也基本一致。只是生成的方式不太一样。
2.比较
1)装饰者
装饰属于行为型模式,目的在于动态将责任(行为)加到对象上。
类图
a. 装饰者和具体对象有共同父类
b. 装饰者持有父类引用
c.以上两者设计,都为了方便的进行一层层的包装。
2)适配器
解决兼容问题
a. 适配器隔绝了客户(Client)和被适配者(Adaptee)【封装】
b. 适配器承担了中间转换的角色
3.小结
从根源出发,根据需求,一步一步演变推进。
对于设计模式的比较,要先从设计初衷出发。了解设计的精髓之处,不停留在一知半解。