代理模式
秒懂Java代理与动态代理模式
用代理对象代替目标对象来实现某个目的(服务/主题/功能)。
目的
- 隐藏目标对象
- 增强目标对象
代理模式结构
代理模式 | Refactoring.Guru
服务接口
声明了服务接口。 代理必须遵循该接口才能伪装成服务对象。
服务类
提供了一些实用的业务逻辑。
代理类
代理类包含一个指向服务对象的引用成员变量。 代理完成其任务 (例如延迟初始化、 记录日志、 访问控制和缓存等) 后会将请求传递给服务对象。 通常情况下, 代理会对其服务对象的整个生命周期进行管理。
客户端
客户端能通过同一接口与服务或代理进行交互,所以你可在一切需要服务对象的代码中使用代理。
静态代理
劳动仲裁案例:代理律师代理讨薪员工索要工资。
服务接口
代理主题:讨薪
1 2 3 4
| public interface AskAbility {
public void askForPay(); }
|
服务类
1 2 3 4 5 6
| public class ZhangSan implements AskAbility { @Override public void askForPay() { System.out.println("还钱!"); } }
|
代理类
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class Lawyer implements AskAbility { private ZhangSan zhangSan;
public Lawyer(ZhangSan zhangSan) { this.zhangSan = zhangSan; }
@Override public void askForPay() { zhangSan.askForPay(); System.out.println("如果不还将承担法律责任!"); } }
|
客户端
1 2 3 4 5 6 7 8
| public class Client {
public static void main(String[] args) { ZhangSan zhangSan = new ZhangSan(); AskAbility ask = new Lawyer(zhangSan); ask.askForPay(); } }
|
动态代理
静态代理中代理类在编译期已经存在,一个服务类需要一个代理类与之对应,当服务类增多时,代理类随着增多,导致类数量太多。
动态代理就是为了减少类数量而产生。
动态代理有 JDK(基于接口、反射生成) 和 CGLIB(基于继承、字节码生成) 两种实现方式。
Spring AOP 就是基于动态代理实现的。
关于 Spring AOP (AspectJ) 你该知晓的一切
Spring系列教材 (三)- 注解方式 IOC/DI
JDK 动态代理
两个重要的元素:
InvocationHandler 接口
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
- proxy:动态代理对象
- method:正在执行的方法
- args:当前执行方法传入的实参
Proxy 类
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class AskingHandler implements InvocationHandler {
private Object target;
public AskingHandler(Object target) { this.target = target; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object invoke = method.invoke(target, args); System.out.println("如果不还将承担法律责任!"); return invoke; } }
|
1 2 3 4 5 6 7 8 9
| public class Client {
public static void main(String[] args) { Employee employee = new Employee(); InvocationHandler handler = new AskingHandler(employee); AskAbility proxy = (AskAbility) Proxy.newProxyInstance(employee.getClass().getClassLoader(), employee.getClass().getInterfaces(), handler); proxy.askForPay(); } }
|
CGLIB 动态代理
JDK 只能对实现了接口的类做动态代理,而不能对没有实现接口的类做动态代理,所以出现了 cgLib。
CGLib(Code Generation Library)是一个强大、高性能的 Code 生成类库,它可以在程序运行期间动态扩展类或接口,它的底层是使用 java字节码操作框架 ASM 实现。
CGLIB 两个重要元素:
MethodInterceptor 方法拦截器
Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable;
Enhancer
1 2 3 4 5 6
| public static Object create(Class type, Callback callback) { Enhancer e = new Enhancer(); e.setSuperclass(type); e.setCallback(callback); return e.create(); }
|
服务类
1 2 3 4 5 6
| public class Employee {
public void askForPay() { System.out.println("还钱!"); } }
|
方法拦截器
1 2 3 4 5 6 7 8 9 10
| public class AskingMethodInterceptor implements MethodInterceptor {
@Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { Object result = methodProxy.invokeSuper(o, objects); if (method.getName().equals("askForPay")) System.out.println("如果不还将承担法律责任!"); return result; } }
|
客户端
1 2 3 4 5 6 7 8 9
| public class Client {
public static void main(String[] args) { Employee employee = new Employee(); Employee proxy = (Employee) Enhancer.create(employee.getClass(), new AskingMethodInterceptor());
proxy.askForPay(); } }
|