代理模式
定义
代理模式是对象的结构模式。代理模式给某一个对象提供代理对象,并有代理对象控制对源对象的应用。
好处
我们在写一个功能函数时,经常需要在其中写入与功能不是直接相关但很有必要的代 码,如日志记录,信息发送,安全和事务支持等,这些枝节性代码虽然是必要的,但它会带来以下麻烦:
- 枝节性代码游离在功能性代码之外,它不是函数的目的,这是对OO是一种破坏
- 枝节性代码会造成功能性代码对其它类的依赖,加深类之间的耦合,可重用性降低
- 从法理上说,枝节性代码应该
监视着功能性代码,然后采取行动,而不是功能性代码
通知枝节性代码采取行动,这好比吟游诗人应该是主动记录骑士的功绩而不是骑士主动要求诗人记录自己的功绩
结构
角色
- 抽象对象角色:声明了目标对象和代理对象的共同接口,这样在任何可以使用目标对象的地方都可以使用代理对象
- 目标对象角色:定义了代理对象所代表的目标对象
- 代理对象角色:代理对象内部包含目标对象的引用,从而可以在任何时候操作目标对象。代理对象提供与目标对象相同的接口,可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或之后,执行某个操作。而非单纯的把调用传递给目标对象。
静态代理
静态代理在使用时,要定义好接口或者父类,被代理对象和真实对象继承相同的接口或父类。
静态代理中,一个目标对象对应一个代理对象,彼此的关系和类型都需要在编译前约定好。
缺点:存在代码重复、不利于代码的后续维护、灵活性不高
Movie
1 | public interface Movie { |
TwelveMonkeysMovie
1 | public class TwelveMonkeysMovie implements Movie { |
Cinema
1 | public class Cinema implements Movie { |
Main
1 | public static void main(String[] args) { |
动态代理(JDK代理)
特点
运行期间,通过 反射机制 创建实现了一组给定接口的类
在运行时生成的
class
要实现给定的一组interface
,因此class
的实例可以当做interface
的任何一个来使用。同时要提供一个
handler
,接管实际的工作。接口中声明的方法被转移到调用处理器的
InvocationHandler.invoke
集中处理,在接口方法数量多的回收可以灵活处理,使类职责更加单一,复用性更强。
使用JDK
反射动态生成类,不需要第三方库就可以代理,使用条件:
必须实现
InvocationHandler
接口;使用
Proxy.newProxyInstance
产生代理对象;被代理的对象必须要实现接口;
API
代理类所在的包:java.lang.reflect.Proxy
使用其静态方法:static Object newProxyInstance(ClassLoader loader, Class [] interfaces, InvocationHandler handler)
实现代理。
ClassLoader loader
: 指定当前目标对象使用类加载器,用null表示默认类加载器Class [] interfaces
: 需要实现的接口数组InvocationHandler handler
: 调用处理器,执行目标对象的方法时,会触发调用处理器的方法,从而把当前执行目标对象的方法作为参数传入
java.lang.reflect.InvocationHandler
:这是调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。
1 | // 该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例,第二个参数是被调用的方法对象 |
代码
DemoInterface(目标类实现的接口)
1 | public interface DemoInterface { |
ProxyFactory(代理类)
1 | public class ProxyFactory { |
Main(测试)
1 | public static void main(String[] args) { |
Cglib 代理(子类代理)
静态代理和Jdk动态代理都要求目标对象实现一个接口或多个接口(静态代理代理对象也需要实现接口)。
当目标对象未实现任何接口,可以使用构建目标对象之类的方法实现动态代理,即 Cglib
。
底层实现:使用字节码处理框架 ASM
转换字节码并生成新的子类。
API
自定义
MethodInterceptor
实现类,实现方法:1
2
3
4
5
6
7/**
* sub:cglib生成的代理对象
* method:被代理对象方法
* objects:方法入参
* methodProxy: 代理方法
*/
Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)生成
CGLIB
代理对象1
2
3
4
5
6
7
8
9
10
11
12
13
14/**
* 为目标对象创建代理对象
*/
public Object getProxyInstance() {
// 增强器
Enhancer en = new Enhancer();
// 设置父类
en.setSuperclass(target.getClass());
// 设置回调对象, 即 MethodInterceptor
// 方法上是 Callback<T> 即可
en.setCallback(this);
// 创建类
return en.create();
}调用目标代理对象方法
Code
ProxyFactory(代理工厂)
1 | public class ProxyFactory implements MethodInterceptor { |
Main(测试)
1 | public static void main(String[] args) { |