Spring-Aop源码解析(中)

Spring-Aop源码解析(上)上文讲解了到底什么是Aop,以及围绕方法该如何去找对应的增强点,包括整个Advisor链路的执行顺序,本文来对上文中存在的一些关键点进行一个深入挖掘

Advice:要增强的逻辑,就是我们执行额外逻辑的那坨代码,比如要在test方法之前横向插入一段逻辑,那么我们就需要实现BeforeAdvice接口,来重写里面的before方法。

JointPoint:具体要增强的哪个点,比如我要对UserService下的test方法进行增强,那么test方法就是JointPoint

PointCut:切入点,我要对哪一些点进行增强, 这些点就被我们称为PointCut,就是一类JoinPoint

Advisor:PointCut+Advice,我要对哪一类进行一个额外的逻辑增强,Advisor可以理解为一种行为

下面的代码可以一目了然:

        设置一个Advisor,并且在Advisor中可以设置PointCut和Advice,PointCut中又分为ClassFilter过滤和MethodMatcher过滤,MethodMatcher中的runtime属性设置成true的时候会对方法中的参数进行一个额外的逻辑校验。Advice就是我们自己要实现的增强逻辑,所以这段代码翻译成中文就是,我要对UserService下的test方法,并且test方法中只有一个参数的这个方法进行前置逻辑的增强。那么在Spring中是如何实现这段逻辑的

		proxyFactory.addAdvisor(new PointcutAdvisor() {@Overridepublic Pointcut getPointcut() {return new Pointcut() {@Overridepublic ClassFilter getClassFilter() {return 	new ClassFilter() {@Overridepublic boolean matches(Class<?> clazz) {//只对UserSer的类进行增强return UserService.class.equals(clazz);}};}@Overridepublic MethodMatcher getMethodMatcher() {return new MethodMatcher() {@Overridepublic boolean matches(Method method, Class<?> targetClass) {//只对UserService下的test方法进行增强if(method.equals("test")){return true;}return false;}@Overridepublic boolean isRuntime() {//如果这边设置成true,那么下面那个matches才会生效return true;}@Overridepublic boolean matches(Method method, Class<?> targetClass, Object... args) {//根据方法中的参数进行额外逻辑的判断if(args.length == 1){return true;}return false;}};}};}@Overridepublic Advice getAdvice() {//实现了BeforeAdvice的一个类return new MyBeforeAdvice();}@Overridepublic boolean isPerInstance() {return false;}});

        在Spring-Aop源码解析(上)篇中,我们遗留了一个方法getCallbacks的方法,这里面就是Spring处理这些Advisor的实现逻辑,getCallBacks中核心逻辑如下

	private Callback[] getCallbacks(Class<?> rootClass) throws Exception {//获取被代理对象的所有方法Method[] methods = rootClass.getMethods();Callback[] fixedCallbacks = new Callback[methods.length];for (int x = 0; x < methods.length; x++) {Method method = methods[x];//将方法和被代理类传入,进行Advisor的过滤,到底哪些Advisor是被我需要的List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);//针对于我要增强的方法和类得到的代理链(Advice链),生成一个Interceptor,然后缓存fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());this.fixedInterceptorMap.put(method, x);}}

        继续追踪源码:AdvisedSupport.getInterceptorsAndDynamicInterceptionAdvice->DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice,这块代码的逻辑就完美呈现了PointCut到底是如何去匹配的,如果匹配,就将该Advisor转换成成MethodInterceptor(这里面会借用适配器去强行转换),所以最后我们返回的就是针对于匹配到的被代理对象的一串List<MethodInterceptor>,上文中的疑惑(DynamicMethodMatcher到底是啥玩意,包括Advisor是如何整合成MethodInterceptor的)也在本文中得到了解析

	public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass) {// 从ProxyFactory中拿到所设置的Advice(添加时被封装成了DefaultPointcutAdvisor)// 添加的时候会控制顺序//这个Advisor是怎么塞进去的会在后续章节详细讲解,主要是在Bean的生命周期初始化后那边塞得Advisor[] advisors = config.getAdvisors();List<Object> interceptorList = new ArrayList<>(advisors.length);Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());for (Advisor advisor : advisors) {if (advisor instanceof PointcutAdvisor) {PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;// 先匹配类if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {// 再匹配方法MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();boolean match = mm.matches(method, actualClass);if (match) {// 如果匹配则将Advisor封装成为Interceptor,当前Advisor中的Advice可能即是MethodBeforeAdvice,也是ThrowsAdviceMethodInterceptor[] interceptors = registry.getInterceptors(advisor);if (mm.isRuntime()) {//如果是runTIme属性被设置成true,那么会将它封装成Dynamic类型,就是针对方法额外做了一个参数的匹配for (MethodInterceptor interceptor : interceptors) {interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));}}else {interceptorList.addAll(Arrays.asList(interceptors));}}// 最终,interceptorList中存储的是当前正在执行的Method所匹配的MethodInterceptor,可能动态的,也可能是非动态的,// 找到Method所匹配的MethodInterceptor后,就会开始调用这些MethodInterceptor,如果是动态的,会额外进行方法参数的匹配}}}}//Advisor是如何转换成MethodInterceptor的@Overridepublic MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {List<MethodInterceptor> interceptors = new ArrayList<>(3);Advice advice = advisor.getAdvice();//如果默认是MethodInterceptor,那么就直接转if (advice instanceof MethodInterceptor) {interceptors.add((MethodInterceptor) advice);}//借助于适配器,将其转换成MethodInterceptor// 将Advice适配成MethodInterceptorfor (AdvisorAdapter adapter : this.adapters) {if (adapter.supportsAdvice(advice)) {interceptors.add(adapter.getInterceptor(advisor));}}if (interceptors.isEmpty()) {throw new UnknownAdviceTypeException(advisor.getAdvice());}return interceptors.toArray(new MethodInterceptor[0]);}

总结:

        Advisor中可以自行的设置PointCut和Advice,在方法执行的时候(method.invoke())PointCut则会对被代理对象的类和方法进行匹配,如果匹配成功,那么就会将该Advisor打包成一个MethodInterceptor链(因为可能有很多增强逻辑,针对于同一个类或者方法),然后返回。匹配逻辑则是先匹配类,在匹配方法,如果runTime属性设置成true,那么会再去匹配方法中的参数是否匹配,然后针对于参数这种情况会返回一个DynamicMethodMatcher(上文中有讲解到这是在哪用的)

        将Advisor转换成MethodInterceptor的适配器如下,Spring-Aop并没有提供给我们AfterAdvice的适配器,但是Aspectj里面有就是@After注解(AspectJAfterAdvice),你要的话可以自己使用,他是实现了MethodInterceptor接口的,所以在之前就可以直接强转了,不用这些适配器

	public DefaultAdvisorAdapterRegistry() {registerAdvisorAdapter(new MethodBeforeAdviceAdapter());registerAdvisorAdapter(new AfterReturningAdviceAdapter());registerAdvisorAdapter(new ThrowsAdviceAdapter());}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/822255.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

养猫必看!毛发护理秘籍,猫粮选择大揭秘!

亲爱的猫友们&#xff0c;我们都知道&#xff0c;猫咪的毛发是它们健康与美丽的象征。选择一款合适的猫粮&#xff0c;对于猫咪的毛发健康至关重要。那么&#xff0c;如何根据猫咪的毛发情况来选择合适的猫粮呢&#xff1f;接下来&#xff0c;就让我来为你详细解答吧&#xff0…

PDF文档电子签名怎么做?

如何确保电子文档的签署具有公信力和法律效力&#xff0c;防止伪造和假冒签名等问题&#xff0c;是电子文档无纸化应用面临的重要挑战。本文将详细介绍PDF文档电子签名的概念、重要性、实施步骤以及相关的法律背景&#xff0c;帮助用户理解并有效应用PDF文档电子签名技术。 1.…

Unity HDRP 2021 Release-Notes

&#x1f308;Unity HDRP 2021 Release-Notes 本文信息收集来自自动搜集工具&#x1f448; 版本更新内容2021.3.33HDRP: Added additional documentation for cached shadows of directional lights.2021.3.33HDRP: Added in which space custom velocity should be computed.…

lv_micropython for ESP32-S2/S3/C3

一、更新文件 lv_binding_micropython:GitHub - kdschlosser/lv_binding_micropython at esp32-s-c-h_support 下载lv_binding_micropython分支&#xff1a; git clone -b esp32-s-c-h_support https://github.com/kdschlosser/lv_binding_micropython.git 替换文件&#x…

如何高效解决电商API中的订单问题?

随着电子商务的迅猛发展&#xff0c;订单处理成为电商企业运营中的关键环节。为了提高订单处理的效率和质量&#xff0c;电商API&#xff08;应用程序接口&#xff09;的应用逐渐受到重视。本文将深入探讨电商API在订单处理中的高效解决方案&#xff0c;帮助电商企业优化订单处…

安装指定版本的ant-design-vue和指定版本的@ant-design/icons-vue 图标组件包

前言&#xff1a; 最近在完成公司的项目时&#xff0c;为了兼容其他的版本&#xff0c;需要安装指定版本的ant-design-vue和ant-design/icons-vue 图标组件包&#xff0c;安装成功之后&#xff0c;分享如下&#xff1a; 安装命令&#xff1a; ant-design-vue&#xff1a; 不…

【MATLAB源码-第54期】基于白鲸优化算法(WOA)和遗传算法(GA)的栅格地图路径规划最短路径和适应度曲线对比。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 1.白鲸优化算法&#xff08;WOA&#xff09;&#xff1a; 白鲸优化算法是一种受白鲸捕食行为启发的优化算法。该算法模拟了白鲸群体捕食的策略和行为&#xff0c;用以寻找问题的最优解。其基本思想主要包括以下几点&#xff…

Docker 学习笔记(九):Docker 网络原理,理解 docker0,虚拟网卡,容器互联,以及跨网络连通

一、前言 记录时间 [2024-4-16] 系列文章简摘&#xff1a; Docker 学习笔记&#xff08;六&#xff09;&#xff1a;挑战容器数据卷技术一文通&#xff0c;实战多个 MySQL 数据同步&#xff0c;能懂会用&#xff0c;初学必备 Docker 学习笔记&#xff08;七&#xff09;&#x…

Unity HDRP 2023 Release-Notes

&#x1f308;Unity HDRP 2023 Release-Notes 本文信息收集来自自动搜集工具&#x1f448; 版本更新内容2023.2.17HDRP: Fixed game view flicker while on HDR and Reflection probe.(UUM-64343)2023.2.17HDRP: HDRP: Fixed invalid AABB error in the console when using th…

C# 截图并保存为图片

在winform开发中&#xff0c;有时会用到截图并保存为图片的时候&#xff0c;这里列了三种保存图片的可能情况。 将窗体截图保存成图片的方式是&#xff1a; Bitmap bit new Bitmap(this.Width, this.Height);//实例化一个和窗体一样大的bitmap Graphics g Graphics.FromImag…

Redis 核心知识点常考面试题(持续更新中)

Redis 核心知识点常考面试题&#xff08;持续更新中&#xff09; Redis单线程IO多路复用原理Redis缓存穿透、缓存雪崩、缓存击穿问题Redis与数据库双写不一致问题基于Redis实现分布式锁的的应用场景Redis持久化方式Redis内存淘汰机制Redis删除策略Redis主从复制、哨兵、集群Red…

AI时代的教育革命:智能教育的未来展望

人工智能技术正在以前所未有的速度和规模改变着我们的世界&#xff0c;而教育领域也不例外。本文将探讨人工智能在教育领域的应用现状和未来发展趋势&#xff0c;介绍智能教育的核心概念和关键技术&#xff0c;并通过案例分析和实践指南&#xff0c;展望智能教育的未来&#xf…

速盾:jquery可以用cdn加速吗?

CDN&#xff08;Content Delivery Network&#xff09;是一种优化网络传输的技术&#xff0c;通过将网站的相关静态资源缓存到全球各地的服务器节点上&#xff0c;可以加速网站的访问速度。jQuery是一款非常流行的JavaScript库&#xff0c;用于简化网页开发中的DOM操作、事件处…

回归损失函数

目录 1 MAE 2 MSE 3 MAPE 4 Quantile Loss分位数损失 回归损失函数也可以做为评价指标使用&#xff0c;但是有没有想过数据分布与损失函数之间的关系呢&#xff01; 使用特定损失函数的前提是我们对标签的分布进行了某种假设&#xff0c;在这种假设的前提下通过极大似然法推…

降低Altium Designer许可使用成本

在电子设计行业中&#xff0c;Altium Designer等EDA&#xff08;电子设计自动化&#xff09;软件是不可或缺的工具。然而&#xff0c;随着业务的增长&#xff0c;许可使用成本也成为企业关注的焦点。本文将探讨如何减少Altium Designer的许可使用成本&#xff0c;提高企业经济效…

GPT-3和自然语言处理的前沿:思考AI大模型的发展

引言 自然语言处理&#xff08;NLP&#xff09;是人工智能&#xff08;AI&#xff09;领域中最富有挑战性和活跃的研究领域之一。近年来&#xff0c;随着深度学习技术的发展和计算能力的提高&#xff0c;大型语言模型&#xff0c;尤其是OpenAI的GPT-3&#xff0c;已成为推动该…

基于微信小程序投票评选系统的设计与实现(论文+源码)_kaic

摘 要 社会发展日新月异&#xff0c;用计算机应用实现数据管理功能已经算是很完善的了&#xff0c;但是随着移动互联网的到来&#xff0c;处理信息不再受制于地理位置的限制&#xff0c;处理信息及时高效&#xff0c;备受人们的喜爱。所以各大互联网厂商都瞄准移动互联网这个潮…

攻防世界10-disabled_button

10-disabled_button 法1&#xff1a;修改html的标签内容 首先看题目描述提到前端知识&#xff0c;联想到HTML&#xff0c;提示是一个不能按的按钮&#xff0c;结合题目名button很明显是涉及到HTML button标签知识&#xff0c;最后通过disabled提示应该是按钮被禁用了 知识补充…

优橙内推重庆专场——5G网络优化(中高级)工程师

可加入就业QQ群&#xff1a;374637347 联系老师内推简历投递邮箱&#xff1a;hrictyc.com 内推公司1&#xff1a;北京电旗通讯技术股份有限公司 内推公司2&#xff1a;浙江明讯网络技术有限公司 内推公司3&#xff1a;杭州东信网络技术有限公司 北京电旗通讯技术股份有限公…

PySide QWebChannel实现Python与JS双向通信的前后端分离桌面应用

文章目录 一、前言二、实现方法1.前端部分2.后端部分3.依赖文件三、运行结果一、前言 以往开发桌面应用通常都是页面接口一起写,这样开发周期比较长,且页面样式不灵活,如果能把页面交给前端写的话,就可前后端并行开发桌面应用了,并且css语言灵活好用样式丰富。下面介绍一…