代理模式
定义: 代理是一个包装器或代理对象,客户端正在调用它来访问幕后的真实服务对象。使用代理可以简单地转发到真实对象,或者可以提供额外的逻辑。
wiki:https://en.wikipedia.org/wiki/Proxy_pattern
类型: 结构型模式
UML类图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| @startuml proxy
class Client{
}
interface Subject{ + method() }
class Proxy{ + method() }
class RealSubject{ + method() }
Client ..> Subject
Subject <|-- RealSubject
Subject <|-- Proxy
Proxy ..> RealSubject
@enduml
|
代理模式实例
静态代理
结构如下:
抽象主题角色(公共接口)
1 2 3 4
| public interface Subject { void method(); }
|
具体主题角色(真正的处理对象)
1 2 3 4 5 6 7
| public class RealSubject implements Subject{ @Override public void method() { System.out.println("do something..."); } }
|
代理主题角色(代理类)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class Proxy implements Subject{ private Subject subject;
public Proxy(Subject subject){ this.subject = subject; }
@Override public void method() { this.before(); this.subject.method(); this.after(); }
public void before(){ System.out.println(">>> Proxy Before..."); }
public void after(){ System.out.println(">>> Proxy After..."); } }
|
客户端(业务类)
1 2 3 4 5 6 7 8
| public static void main(String[] args) { RealSubject realSubject = new RealSubject(); Proxy proxy = new Proxy(realSubject); proxy.method(); }
|
动态代理
例如面向横切面编程-AOP(Aspect Oriented Programming)
中就运用了动态代理机制.
JDK实现
UML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| @startuml class Client{
}
class DynamicProxy{
}
interface InvocationHandler { + Object invoke() }
class CustomInvocationHandler{ + Object invoke() }
interface Advice{ + void exec() }
class BeforeAdvice{ + void exec() }
interface Subject{ + void method() }
class RealSubject{ + void method() }
Subject <|.. RealSubject
Client --> DynamicProxy
Client --> Subject
DynamicProxy --> InvocationHandler
DynamicProxy --> Advice
Advice <|.. BeforeAdvice
InvocationHandler <|.. CustomInvocationHandler
note "Do Something before invoke" as N1 N1 .. Advice @enduml
|
真正执行的主题
1 2 3 4 5 6 7 8 9 10 11
| public interface Subject { void method(); }
public class RealSubject implements Subject{
@Override public void method() { System.out.println("do something..."); } }
|
消息通知
1 2 3 4 5 6 7 8 9 10
| public interface Advice { void exec(); }
public class BeforeAdvice implements Advice { @Override public void exec() { System.out.println(">>> BeforeAdvice working..."); } }
|
实现JDK的InvocationHandler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class CustomInvocationHandler implements InvocationHandler{
private Object target;
public CustomInvocationHandler(Object target) { this.target = target; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(this.target,args); } }
|
动态代理类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public final class DynamicProxy {
private static final Advice beforeAdvice = new BeforeAdvice();
public static <T extends Subject> T newProxyInstance(Subject target){
beforeAdvice.exec(); return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new CustomInvocationHandler(target)); } }
|
场景类
1 2 3 4 5 6 7 8
| public class Client { public static void main(String[] args) { final Subject o = DynamicProxy.newProxyInstance(new RealSubject()); o.method(); } }
|
CGLIB实现
UML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| @startuml cglib proxy class Subject{ + method() }
package net.sf.cglib <<Cloud>> { interface MethodInterceptor{ + intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable:Object } }
class CglibProxyFactory{ - target:Object + CglibProxyFactory(Object target) + getInstance():Object + intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable:Object }
class Client{ }
MethodInterceptor <..- CglibProxyFactory
Client --> CglibProxyFactory
Client --> Subject @enduml
|
主题类
1 2 3 4 5 6
| public class Subject { public String method(){ System.out.println("Hello World!"); return "ok"; } }
|
代理工厂类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| public class CglibProxyFactory implements MethodInterceptor {
private Object target;
public CglibProxyFactory(Object target) { this.target = target; }
public Object getInstance(){ Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.target.getClass()); enhancer.setCallback(this);
return enhancer.create(); }
@Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("Transaction Open..."); final Object invoke = method.invoke(target, args); System.out.println("Transaction Commit..."); return invoke; } }
public class CglibProxyFactory2 {
private Object target;
public CglibProxyFactory2(Object target) { this.target = target; }
public Object getInstance(){ Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("Transaction Open..."); final Object invoke = method.invoke(target, args); System.out.println("Transaction Commit..."); return invoke; } }); return enhancer.create(); } }
|
场景类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| public class Client { public static void main(String[] args) { Subject subject = new Subject();
CglibProxyFactory proxy = new CglibProxyFactory(subject); final Subject proxyObject = (Subject) proxy.getInstance(); proxyObject.method();
System.out.println(proxyObject.getClass());
CglibProxyFactory2 factory2 = new CglibProxyFactory2(subject);
final Subject instance = (Subject)factory2.getInstance(); System.out.println(instance.method());
System.out.println(factory2.getInstance().getClass());
} }
|
几种代理的对比
静态代理: 由程序员或特定工具自动生成的源代码,再对其编译,在程序运行之前,代理的类编译生成的.class
文件就已经存在了
动态代理: 在程序运行时,通过反射机制动态创建而成。
代理方式 |
具体实现 |
优点 |
缺点 |
底层 |
静态代理 |
代理类与委托类实现同一接口 在代理类中需要硬编码接口 |
实现简单 容易理解 |
代理类需要硬编码接口 在实际应用中可能会导致重复编码 浪费存储空间并且效率很低 |
|
JDK动态代理 |
代理类与委托类实现同一接口 主要是通过代理类实现InvocationHandler 并重写invoke 方法来进行动态代理 在invoke方法中将对方法进行增强处理 |
不需要硬编码接口 代码复用率高 |
只能够代理实现了接口的委托类 |
用反射机制进行方法的调用 |
CGLIB动态代理 |
代理类将委托类作为自己的父类并为其中的非final 委托方法创建两个方法 一个是与委托方法签名相同的方法,它在方法中会通过super调用委托方法 另一个是代理类独有的方法 在代理方法中,它会判断是否存在实现了MethodInterceptor 接口的对象,若存在则将调用intercept 方法对委托方法进行代理 |
可以在运行时对类或者是接口进行增强操作 委托类无需实现接口 |
不能对final类 以及final方法 进行代理 |
底层将方法全部存入一个数组中, 通过数组索引直接进行方法调用 |