在代理模式(Proxy Pattern)属于结构型模式。在代理模式中,我们对一个对象提供一个代理对象,使用代理对象控制原对象的引用,目的是为了透明的控制对象访问
Java中的代理按照代理类生成时机不同分为静态代理和动态代理,静态代理的代理类在编译器就生成,而动态代理的代理类在Java运行时动态生成。动态代理又分为JDK代理和CGLib代理。
业务代码
/** * 静态代理 */ public interface Pay { void pay(); } //真实类 class Alipay implements Pay { @Override public void pay() { System.out.println("支付宝支付"); } } //代理类 class AlipayProxy implements Pay{ //组合真实对象 private final Alipay alipay = new Alipay(); @Override public void pay() { long startTime = System.currentTimeMillis(); alipay.pay(); System.out.println("执行了" + (System.currentTimeMillis()-startTime) + "毫秒"); //支付宝支付 执行了0毫秒 } }
测试代码
public class Client { public static void main(String[] args) { new AlipayProxy().pay(); } }
优点
缺点
为了弥补静态代理的缺点,引入了动态代理
1.JDK动态代理(利用Java提供的代理机制)
业务代码
/** * JDK动态代理 */ public interface Pay { void pay(); } //真实类 class Alipay implements Pay { @Override public void pay() { System.out.println("支付宝支付"); } } class PayProxy { //组合真实对象 private Pay pay; public PayProxy(Pay pay) { this.pay = pay; } public Pay getProxy() { return (Pay) Proxy.newProxyInstance(getClass().getClassLoader(), pay.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long startTime = System.currentTimeMillis(); Object result = method.invoke(pay, args); System.out.println("执行了" + (System.currentTimeMillis() - startTime) + "毫秒"); return result; } }); } }
测试代码
public class Client { public static void main(String[] args) { PayProxy payProxy = new PayProxy(new Alipay()); Pay pay = payProxy.getProxy(); pay.pay(); //支付宝支付 执行了0毫秒 } }
我们通过arthas工具进行反编译,可以找到真正的代理类$Proxy0
//代理对象 public final class $Proxy0 extends Proxy implements Pay { private static Method m3; public $Proxy0(InvocationHandler invocationHandler) { super(invocationHandler); } static { // 通过反射获取名叫pay的menthod m3 = Class.forName("com.designpattern.structure.proxy.v2.Pay").getMethod("pay", new Class[0]); return; } public final void pay() { // h是invocationHandler对象 this.h.invoke(this, m3, null); return; } }
总结执行流程如下
2.CGLib动态代理
JDK动态代理要求必须定义接口,如果没有定义接口,就可以使用CGLib动态代理,CGLib为JDK的动态代理提供了很好的补充
首先引入cglib-3.3.0.jar与asm-9.0.jar
业务代码
//真实对象 class Alipay implements Pay { @Override public void pay() { System.out.println("支付宝支付"); } } class AlipayProxy implements MethodInterceptor { //组合真实对象 private Alipay alipay = new Alipay(); public Alipay getProxy(){ Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Alipay.class); //设置回调函数 enhancer.setCallback(this); //返回代理对象 return (Alipay) enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { long startTime = System.currentTimeMillis(); Object result = method.invoke(alipay, args); System.out.println("执行了" + (System.currentTimeMillis() - startTime) + "毫秒"); return result; } }
测试代码
public class Client { public static void main(String[] args) { Alipay proxy = new AlipayProxy().getProxy(); proxy.pay(); //支付宝支付 执行了0毫秒 } }
优点
缺点
1.功能扩展:日志、监控、事务
2.控制管理:权限、限流
3.远程代理:FeignClient、RMI
4.动态逻辑:mybatis mapper、jpa
5.延迟加载:虚代理
上文提到静态代理是一个具体类产生一个代理类,可能会造成类爆炸,我们现在反观动态代理则是一个接口产生一个代理类,也可能会造成类爆炸,所以这里给出一个较为通用的实现
业务代码
//记录执行的时间的通用类 public class TimeRecordProxy<T> { private final T target; public TimeRecordProxy(T target) { this.target = target; } @SuppressWarnings("unchecked") public T getProxy() { return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this::invoke); } private Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException { long startTime = System.currentTimeMillis(); Object result = method.invoke(target, args); System.out.println("执行了" + (System.currentTimeMillis()-startTime) + "毫秒"); return result; } }
测试代码
public class Client { public static void main(String[] args) { TimeRecordProxy<Pay> timeRecordProxy = new TimeRecordProxy<>(new Alipay()); timeRecordProxy.getProxy().pay(); //支付宝支付 执行了0毫秒 } }
Spring AOP是代理模式的典型应用
到此这篇关于Java结构型模式之代理模式详解的文章就介绍到这了,更多相关Java代理模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
编程 | 2023-02-24 21:36
编程 | 2023-02-21 12:51
编程 | 2023-02-21 12:47
编程 | 2023-02-21 00:15
编程 | 2023-02-21 00:08
编程 | 2023-02-20 21:46
编程 | 2023-02-20 21:42
编程 | 2023-02-20 21:36
编程 | 2023-02-20 21:32
编程 | 2023-02-20 18:12
网友评论