文章目录
一、代理设计模式
组成
代理模式包含如下角色:
- Subject:抽象角色。通过接口或抽象类声明真实角色实现的业务方法。
- Proxy:代理角色。实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
- RealSubject:真实角色。实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
分类
代理可分为静态代理和动态代理,静态代理需要自己按照上面的UML类图来实现,并且在是在编译时就已经确定了代理,而Java提供了动态代理的方式,在反射包下面的DynamicProxy中,可以通过Proxy来运行时完成动态代理。
静态代理UML结构图
静态代理模式示例
首先创建抽象角色:
/*
* 抽象主题角色
* 为真实主题角色以及代理主题角色统一接口
* */
public interface Subject {
void doSomething();
}
然后创建真实角色并实现抽象角色接口
/*
* 真实角色
* 实现了抽线角色接口
* */
public class RealSubject implements Subject,SubjectAnother {
@Override
public void doSomething() {
System.out.println("RealSubject doSomething.");
}
}
其次再创建代理角色,同样也实现抽象角色接口,并且代理角色持有真实角色
/*
* 代理角色
* */
public class Proxy implements Subject {
/*
* 持有一个真实角色的引用
* */
private Subject realSubject;
public Proxy(Subject realSubject){
this.realSubject = realSubject;
}
@Override
public void doSomething() {
// 在真实角色接口前附加职责
System.out.println("Before realSubject.doSomething().");
realSubject.doSomething(); // 调用真实角色的相应接口
System.out.println("After realSubject.doSomething().");
}
}
最后让我们测试静态代理的效果:
public class Main {
public static void main(String[] args) {
// 创建真实角色对象
Subject realSubject = new RealSubject();
// 用代理对象代理真实角色对象
Subject proxySubject = new Proxy(realSubject);
// 调用抽象角色定义的接口
proxySubject.doSomething();
}
}
// 输出结果为:
Before realSubject.doSomething().
RealSubject doSomething.
After realSubject.doSomething().
静态代理的局限性
- 重复性。需要代理的接口越多就要去重复生成一些模板化的代码,不仅麻烦而且不易维护。
- 脆弱性。一旦接口的定义修改,实现了该接口的真实角色以及代理角色的定义也要修改。
动态代理
JVM可以在运行器件动态生成类字节码(名字为$Proxy0),这种动态生成的类通常用来作为代理类,即动态代理类。JVM生成的动态代理类必须实现一个或多个接口,所以JVM生成的动态类只能用作具有相同接口的目标类的代理,如果要为一个没有实现接口的类生成动态代理类,可以使用CGLIB(实际上这也是SPRING框架除了JDK Proxy之外采用的另外一种生成代理类的方法),这里不对CGLIB作具体介绍。
动态代理UML结构图
Java动态代理运用示例(就用刚才静态代理定义的接口以及真实角色):
首先自定义调用处理器(对代理对象的方法的调用最终都会被委派到自定义调用处理器上):
/*
* 自定义调用处理器,必须实现InvocationHandler接口
* */
public class InvocationHandlerImp implements InvocationHandler {
// 被代理对象
private Object object;
public InvocationHandlerImp(Object object){
this.object = object;
}