(一)设计模式之代理模式
一、前言
AOP的拦截功能是由java中的动态代理来实现的。说白了,就是在目标类的基础上增加切面逻辑,生成增强的目标类(该切面逻辑或者在目标类函数执行之前,或者目标类函数执行之后,或者在目标类函数抛出异常时候执行。不同的切入时机对应不同的Interceptor的种类,如BeforeAdviseInterceptor,AfterAdviseInterceptor以及ThrowsAdviseInterceptor等)。那么动态代理是如何实现将切面逻辑(advise)织入到目标类方法中去的呢?下面我们就来详细介绍并实现AOP中用到的两种动态代理。AOP的源码中用到了两种动态代理来实现拦截切入功能:jdk动态代理和cglib动态代理。两种方法同时存在,各有优劣。jdk动态代理是由java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的。总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。还有一点必须注意:jdk动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,jdk动态代理不能应用。由此可以看出,jdk动态代理有一定的局限性,cglib这种第三方类库实现的动态代理应用更加广泛,且在效率上更有优势。
二、案例
以用户去飞猪上买票为例,很明显飞猪平台便是一个代理,飞猪平台在替用户购票的基础上,还增加了额外的功能,比如购票前要校验身份证,购票后需要提供凭证给用户。
1、定义购票行为接口,包括获取身份证号、姓名、余额
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 | public interface TicketBuy { /** * 买票 */ void buy(); /** * 获取身份证号 * @return */ String getId(); /** * 获取姓名 * @return */ String getName(); /** * 获取余额 * @return */ Double getMoney(); } |
2、定义用户类,即被代理类
public class Person implements TicketBuy { private String id; private String name; private Double money; @Override public String getId() { return id; } public void setId(String id) { this.id = id; } @Override public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public Double getMoney() { return money; } public void setMoney(Double money) { this.money = money; } @Override public void buy() { this.money --; System.out.println("用户:"+this.getName()+"买一张票,余额还剩:"+money); } }
3、定义飞猪平台类,即代理类
public class FlyPig implements InvocationHandler { private Person target; /** * 获取被代理人资料 * @param target * @return */ public Object getInstance(Person target){ this.target = target; Class clazz = target.getClass(); return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("飞猪平台校验身份证+姓名:"+this.target.getId()+"+"+this.target.getName()); this.target.buy(); System.out.println("打印凭证!"); return null; } }
4、测试类:
public class Test { public static void main(String[] args) { Person person1 = new Person(); person1.setName("张三"); person1.setId("35052511111111111"); person1.setMoney(100.00); TicketBuy proxy = (TicketBuy)(new FlyPig().getInstance(person1)); proxy.buy(); } }
结果
5、解析
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
2017-12-06 (八)Activiti之流程变量和局部流程变量
2017-12-06 (七)Activiti之历史活动查询和历史任务查询和流程状态查询
2017-12-06 (六)Activiti之实现学生请假流程
2017-12-06 (五)Activiti之查看最新版本的流程定义
2017-12-06 (五)Activiti之获取流程定义图片和流程定义删除
2017-12-06 (四)Activiti之流程定义部署之ZIP方式和流程定义查询