1.springaopԴ?码解???
2.å¦ä½ç解SpringçAOPï¼
3.Spring注解驱动开发二狗子让我给他讲讲@EnableAspectJAutoProxy注解
4.Spring源码插播一个创建代理对象的wrapIfNecessary()方法
5.springaopåç
springaopԴ????
本文将简要介绍AOP(面向切面编程)的基础知识与使用方法,并深入剖析Spring AOP源码。码解首先,码解我们需要理解AOP的码解基本概念。
1. **基础知识
**1.1 **什么是码解AOP?
**AOP全称为Aspect Oriented Programming,即面向切面编程。码解辅助源码AOP的码解思想中,周边功能(如性能统计、码解日志记录、码解事务管理等)被定义为切面,码解核心功能与切面功能独立开发,码解然后将两者“编织”在一起,码解这就是码解AOP的核心。
AOP能够将与业务无关、码解却为业务模块共同调用的码解逻辑封装,减少系统重复代码,降低模块间的耦合度,有利于系统的可扩展性和可维护性。
1.2 **AOP基础概念
**解释较为官方,以下用“方言”解释:AOP包括五种通知分类。
1.3 **AOP简单示例
**创建`Louzai`类,添加`LouzaiAspect`切面,并在`applicationContext.xml`中配置。程序入口处添加`"睡觉"`方法并添加前置和后置通知。接下来,我们将探讨Spring内部如何实现这一过程。
1.4 **Spring AOP工作流程
**为了便于理解后面的源码,我们将整体介绍源码执行流程。箱体捉妖指标公式源码整个Spring AOP源码分为三块,结合示例进行讲解。
第一块是前置处理,创建`Louzai`Bean前,遍历所有切面信息并存储在缓存中。第二块是后置处理,创建`Louzai`Bean时,主要处理两件事。第三块是执行切面,通过“责任链+递归”执行切面。
2. **源码解读
**注意:Spring版本为5.2..RELEASE,否则代码可能不同!这里,我们将从原理部分开始,逐步深入源码。
2.1 **代码入口
**从`getBean()`函数开始,进入创建Bean的逻辑。
2.2 **前置处理
**主要任务是遍历切面信息并存储。
这是重点!请务必注意!获取切面信息流程结束,后续操作都从缓存`advisorsCache`获取。
2.2.1 **判断是否为切面
**执行逻辑为:判断是否包含切面信息。
2.2.2 **获取切面列表
**进入`getAdvice()`,生成切面信息。
2.3 **后置处理
**主要从缓存拿切面,与`Louzai`方法匹配,jdk1.8源码包创建AOP代理对象。
进入`doCreateBean()`,执行后续逻辑。
2.3.1 **获取切面
**首先,查看如何获取`Louzai`的切面列表。
进入`buildAspectJAdvisors()`,方法用于存储切面信息至缓存`advisorsCache`。随后回到`findEligibleAdvisors()`,从缓存获取所有切面信息。
2.3.2 **创建代理对象
**有了`Louzai`的切面列表,开始创建AOP代理对象。
这是重点!请仔细阅读!这里有两种创建AOP代理对象方式,我们选择使用Cglib。
2.4 **切面执行
**通过“责任链+递归”执行切面与方法。
这部分逻辑非常复杂!接下来是“执行切面”最核心的逻辑,简述设计思路。
2.4.1 **第一次递归
**数组第一个对象执行`invoke()`,参数为`CglibMethodInvocation`。
执行完毕后,继续执行`CglibMethodInvocation`的`process()`。
2.4.2 **第二次递归
**数组第二个对象执行`invoke()`。
2.4.3 **第三次递归
**数组第三个对象执行`invoke()`。
执行完毕,退出递归,优乐卡盟源码查看`invokeJoinpoint()`执行逻辑,即执行主方法。回到第三次递归入口,继续执行后续切面。
切面执行逻辑已演示,直接查看执行方法。
流程结束时,依次退出递归。
2.4.4 **设计思路
**这部分代码研究了大半天,因为这里不是纯粹的责任链模式。
纯粹的责任链模式中,对象内部有一个自身的`next`对象,执行当前对象方法后,启动`next`对象执行,直至最后一个`next`对象执行完毕,或中途因条件中断执行,责任链退出。
这里`CglibMethodInvocation`对象内部无`next`对象,通过`interceptorsAndDynamicMethodMatchers`数组控制执行顺序,依次执行数组中的对象,直至最后一个对象执行完毕,责任链退出。
这属于责任链,实现方式不同,后续会详细剖析。下面讨论类之间的关系。
主对象为`CglibMethodInvocation`,手游脚本源码继承于`ReflectiveMethodInvocation`,`process()`的核心逻辑在`ReflectiveMethodInvocation`中。
`ReflectiveMethodInvocation`的`process()`控制整个责任链的执行。
`ReflectiveMethodInvocation`的`process()`方法中,包含一个长度为3的数组`interceptorsAndDynamicMethodMatchers`,存储了3个对象,分别为`ExposeInvocationInterceptor`、`MethodBeforeAdviceInterceptor`、`AfterReturningAdviceInterceptor`。
注意!这3个对象都继承了`MethodInterceptor`接口。
每次`invoke()`调用时,都会执行`CglibMethodInvocation`的`process()`。
是否有些困惑?别着急,我将再次帮你梳理。
对象与方法的关系:
可能有同学疑惑,`invoke()`的参数为`MethodInvocation`,没错!但`CglibMethodInvocation`也继承了`MethodInvocation`,可自行查看。
执行逻辑:
设计巧妙之处在于,纯粹的责任链模式中,`next`对象需要保证类型一致。但这里3个对象内部没有`next`成员,不能直接使用责任链模式。怎么办呢?就单独设计了`CglibMethodInvocation.process()`,通过无限递归`process()`实现责任链逻辑。
这就是我们为什么要研究源码,学习优秀的设计思路!
3. **总结
**本文首先介绍了AOP的基本概念与原理,通过示例展示了AOP的应用。之后深入剖析了Spring AOP源码,分为三部分。
本文是Spring源码解析的第三篇,感觉是难度较大的一篇。图解代码花费了6个小时,整个过程都沉浸在代码的解析中。
难度不在于抠图,而是“切面执行”的设计思路,即使流程能走通,将设计思想总结并清晰表达给读者,需要极大的耐心与理解能力。
今天的源码解析到此结束,有关Spring源码的学习,大家还想了解哪些内容,欢迎留言给楼仔。
å¦ä½ç解SpringçAOPï¼
SpringçAOPé¢ååé¢ç¼ç¨ï¼å°±æ¯æ¨ªåçï¼æ¯å¦ç¨åºè¿è¡æ¶é½è¦å»ºæ¥å¿ï¼ç¸å½äºSQLç触åå¨ãSpringæ¯ä¸ä¸ªå¼æ¾æºä»£ç ç设计å±é¢æ¡æ¶ï¼ä»è§£å³çæ¯ä¸å¡é»è¾å±åå ¶ä»åå±çæ¾è¦åé®é¢ï¼å æ¤å®å°é¢åæ¥å£çç¼ç¨ææ³è´¯ç©¿æ´ä¸ªç³»ç»åºç¨ãSpringæ¯äº å¹´å ´èµ·çä¸ä¸ªè½»é级çJava å¼åæ¡æ¶ï¼ç±Rod Johnsonå建ãç®åæ¥è¯´ï¼Springæ¯ä¸ä¸ªåå±çJavaSE/EEfull-stack(ä¸ç«å¼) è½»é级å¼æºæ¡æ¶ã
Springç¹ç¹ï¼
1ãæ¹ä¾¿è§£è¦ï¼ç®åå¼å
éè¿Springæä¾çIoC容å¨ï¼æ们å¯ä»¥å°å¯¹è±¡ä¹é´çä¾èµå ³ç³»äº¤ç±Springè¿è¡æ§å¶ï¼é¿å 硬ç¼ç æé æçè¿åº¦ç¨åºè¦åãæäºSpringï¼ç¨æ·ä¸å¿ å为åå®ä¾æ¨¡å¼ç±»ãå±æ§æ件解æçè¿äºå¾åºå±çéæ±ç¼å代ç ï¼å¯ä»¥æ´ä¸æ³¨äºä¸å±çåºç¨ã
2ãAOPç¼ç¨çæ¯æ
éè¿Springæä¾çAOPåè½ï¼æ¹ä¾¿è¿è¡é¢ååé¢çç¼ç¨ï¼è®¸å¤ä¸å®¹æç¨ä¼ ç»OOPå®ç°çåè½å¯ä»¥éè¿AOPè½»æ¾åºä»ã
3ã声æå¼äºå¡çæ¯æ
å¨Springä¸ï¼æ们å¯ä»¥ä»åè°ç¦é·çäºå¡ç®¡ç代ç ä¸è§£è±åºæ¥ï¼éè¿å£°æå¼æ¹å¼çµæ´»å°è¿è¡äºå¡ç管çï¼æé«å¼åæçåè´¨éã
4ãæ¹ä¾¿ç¨åºçæµè¯
å¯ä»¥ç¨é容å¨ä¾èµçç¼ç¨æ¹å¼è¿è¡å ä¹ææçæµè¯å·¥ä½ï¼å¨Springéï¼æµè¯ä¸åæ¯æè´µçæä½ï¼èæ¯éæå¯åçäºæ ãä¾å¦:Spring对Junit4æ¯æï¼å¯ä»¥éè¿æ³¨è§£æ¹ä¾¿çæµè¯Springç¨åºã
5ãæ¹ä¾¿éæåç§ä¼ç§æ¡æ¶
Springä¸ææ¥åç§ä¼ç§çå¼æºæ¡æ¶ï¼ç¸åï¼Springå¯ä»¥éä½åç§æ¡æ¶ç使ç¨é¾åº¦ï¼Springæä¾äºå¯¹åç§ä¼ç§æ¡æ¶(å¦Struts,HibernateãHessianãQuartz)ççç´æ¥æ¯æã
6ãéä½Java EE APIç使ç¨é¾åº¦
Spring对å¾å¤é¾ç¨çJava EE API(å¦JDBCï¼JavaMailï¼è¿ç¨è°ç¨ç)æä¾äºä¸ä¸ªèèçå°è£ å±ï¼éè¿Springçç®æå°è£ ï¼è¿äºJava EE APIç使ç¨é¾åº¦å¤§ä¸ºéä½ã
7ãJava æºç æ¯ç»å ¸å¦ä¹ èä¾
Springçæºç 设计精å¦ãç»ææ¸ æ°ãå å¿ç¬è¿ï¼å¤å¤ä½ç°ç大å¸å¯¹Java设计模å¼çµæ´»è¿ç¨ä»¥å对Javaææ¯çé«æ·±é 诣ãSpringæ¡æ¶æºç æ çæ¯Javaææ¯çæä½³å®è·µèä¾ãå¦ææ³å¨çæ¶é´å è¿ éæé«èªå·±çJavaææ¯æ°´å¹³ååºç¨å¼åæ°´å¹³ï¼å¦ä¹ åç 究Springæºç å°ä¼ä½¿ä½ æ¶å°ææ³ä¸å°çææã
Spring注解驱动开发二狗子让我给他讲讲@EnableAspectJAutoProxy注解
在配置类上添加@EnableAspectJAutoProxy注解,能够开启注解版的AOP功能。这意味着,如果在AOP中要启用注解版的AOP功能,就需要在配置类上添加@EnableAspectJAutoProxy注解。让我们来看看@EnableAspectJAutoProxy注解的源码,如下所示。
从源码可以看出,@EnableAspectJAutoProxy注解使用@Import注解引入了AspectJAutoProxyRegister.class对象。那么,AspectJAutoProxyRegistrar是做什么的呢?我们点击到AspectJAutoProxyRegistrar类的源码中,如下所示。
可以看到AspectJAutoProxyRegistrar类实现了ImportBeanDefinitionRegistrar接口。我们回顾ImportBeanDefinitionRegistrar接口的定义,如下所示。
通过ImportBeanDefinitionRegistrar接口,我们可以实现将自定义的组件添加到IOC容器中。也就是说,@EnableAspectJAutoProxy注解使用AspectJAutoProxyRegistrar对象自定义组件,并将相应的组件添加到IOC容器中。
在AspectJAutoProxyRegistrar类的registerBeanDefinitions()方法中设置断点,我们以debug的方法来运行AopTest类的testAop()方法。当程序运行到断点位置时,我们可以看到程序已经暂停,IDEA的左下角显示了方法的调用栈。
在registerBeanDefinitions()方法中,首先调用AopConfigUtils类的registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法来注册registry。在registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法中,直接调用了重载的registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法。在重载的registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法中,传入了AnnotationAwareAspectJAutoProxyCreator.class对象。
在registerOrEscalateApcAsRequired()方法中,接收到的Class对象的类型为:org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator。然后,我们继续跟进代码。
在registerOrEscalateApcAsRequired()方法中,首先判断registry是否包含org.springframework.aop.config.internalAutoProxyCreator类型的bean。接下来,我们继续看代码。
最终,AopConfigUtils类的registerOrEscalateApcAsRequired()方法中,会通过registry调用registerBeanDefinition()方法注册组件,并注册的bean的名称为org.springframework.aop.config.internalAutoProxyCreator。
接下来,我们继续看AspectJAutoProxyRegistrar类的registerBeanDefinitions()源码。我们通过AnnotationConfigUtils类的attributesFor方法来获取@EnableAspectJAutoProxy注解的信息。接下来,我们继续判断proxyTargetClass属性的值是否为true,如果为true则调用AopConfigUtils类的forceAutoProxyCreatorToUseClassProxying()方法;继续判断exposeProxy属性的值是否为true,如果为true则调用AopConfigUtils类的forceAutoProxyCreatorToExposeProxy()方法。
综上所述,向Spring的配置类上添加@EnableAspectJAutoProxy注解后,会向IOC容器中注册AnnotationAwareAspectJAutoProxyCreator。
了解了这些之后,我们就可以关注「冰河技术」微信公众号,后台回复不同的关键字获取相应的PDF文档。这些文档都是由冰河原创并整理的超硬核教程,包括《深入浅出Java 种设计模式》、《Java8新特性教程》和《亿级流量下的分布式限流解决方案》,都是面试必备的资料。
最后,如果你觉得这篇文章对你有帮助,别忘了点个赞,给个在看和转发,让更多的人看到,一起学习,一起进步!
Spring源码插播一个创建代理对象的wrapIfNecessary()方法
在深入探讨Spring源码中创建代理对象的`wrapIfNecessary()`方法之前,先简要回顾其作用。`wrapIfNecessary()`方法主要任务是基于一系列条件判断,决定是否为Bean创建代理对象,从而实现AOP(面向切面编程)的功能。下面,我们将逐步解析这一方法的内部逻辑。
`wrapIfNecessary()`方法的执行流程可以分为以下阶段:
1. **条件判断**:
- **已处理Bean**:首先检查传入的Bean是否已处理过,即在`targetSourcedBeans`集合中是否存在该Bean的记录。
- **已创建代理**:接着检查`advisedBeans`集合中是否已有该Bean的代理对象缓存,以确认是否需要再次创建代理。
- **自定义Bean**:通过`isInfrastructureClass()`方法判断是否为Spring自带的Bean,排除此类无需代理的情况。
- **无需代理**:如果上述任一条件满足,则直接返回传入的Bean对象,无需创建代理。
2. **代理创建**:
- **获取Advices和Advisors**:如果上述条件均不满足,则调用`getAdvicesAndAdvisorsForBean()`方法获取当前Bean的Advices和Advisors信息。
- **判断适配**:通过`findEligibleAdvisors()`方法从候选通知器中筛选出适合当前Bean的Advisors,确保这些Advisors可以应用到当前Bean。
- **实现逻辑**:通过`findCandidateAdvisors()`和`findAdvisorsThatCanApply()`方法进一步筛选、拓展、排序Advisors,最终获取到实际需要应用的Adviser集合。
3. **代理构建**:
- **决策**:根据获取的Advisors判断是否需要创建代理。若结果非`DO_NOT_PROXY`,则调用`createProxy()`方法创建代理对象,并缓存以备后续使用。
- **过程**:在创建代理过程中,`exposeTargetClass()`方法设置Bean的属性,`shouldProxyTargetClass()`方法决定使用JDK动态代理还是CGLIB动态代理,`evaluateProxyInterfaces()`方法添加代理接口,最终通过`getProxy()`方法构建代理对象。
4. **优化与扩展**:
- **Advisors排序**:调用`sortAdvisors()`方法对Advisors进行排序,优化代理逻辑执行顺序。
- **扩展与定制**:通过`extendAdvisors()`方法提供扩展点,允许对目标Advisor进行进一步定制。
5. **构建代理对象**:
- **代理工厂**:通过`AopProxyFactory`初始化代理工厂,并在构建代理对象时,考虑接口添加、回调函数配置等,最终通过`createProxy()`方法生成可调用的代理对象。
通过这一系列复杂而有序的过程,`wrapIfNecessary()`方法实现了根据特定条件判断是否创建代理对象,并构建出适用于面向切面编程场景的代理对象,进而增强了应用程序的功能性和灵活性。
springaopåç
åçï¼sping aopæ¯å¯ä»¥éè¿é¢ç¼è¯æ¹å¼åè¿è¡æå¨æ代çå®ç°å¨ä¸ä¿®æ¹æºä»£ç çæ åµä¸ç»ç¨åºå¨æç»ä¸æ·»å åè½çä¸ç§ææ¯ãAOP设计模å¼ååä¸å¦è¿½æ±çæ¯è°ç¨è å被è°ç¨è ä¹é´ç解è¦ï¼AOP å¯ä»¥è¯´ä¹æ¯è¿ç§ç®æ çä¸ç§å®ç°ãå ¶åççç¸å ³ææ¯ï¼
AOPæ¯OOPç延ç»ï¼æ¯Aspect Oriented Programmingç缩åï¼æææ¯é¢ååé¢ç¼ç¨ãAOPï¼è¿éçAOPæçæ¯é¢ååé¢ç¼ç¨ææ³ï¼èä¸æ¯Spring AOPï¼ä¸»è¦ççå®ç°ææ¯ä¸»è¦æSpring AOPåAspectJã
AspectJçåºå±ææ¯æ¯éæ代çï¼å³ç¨ä¸ç§AspectJæ¯æçç¹å®è¯è¨ç¼ååé¢ï¼éè¿ä¸ä¸ªå½ä»¤æ¥ç¼è¯ï¼çæä¸ä¸ªæ°ç代çç±»ï¼è¯¥ä»£çç±»å¢å¼ºäºä¸å¡ç±»ï¼è¿æ¯å¨ç¼è¯æ¶å¢å¼ºï¼ç¸å¯¹äºä¸é¢è¯´çè¿è¡æ¶å¢å¼ºï¼ç¼è¯æ¶å¢å¼ºçæ§è½æ´å¥½ã
Spring AOPéç¨çæ¯å¨æ代çï¼å¨è¿è¡æé´å¯¹ä¸å¡æ¹æ³è¿è¡å¢å¼ºï¼æ以ä¸ä¼çææ°ç±»ï¼å¯¹äºå¨æ代çææ¯ï¼Spring AOPæä¾äºå¯¹JDKå¨æ代ççæ¯æ以åCGLibçæ¯æã
JDKå¨æ代çåªè½ä¸ºæ¥å£å建å¨æ代çå®ä¾ï¼èä¸è½å¯¹ç±»å建å¨æ代çãéè¦è·å¾è¢«ç®æ ç±»çæ¥å£ä¿¡æ¯ï¼åºç¨Javaçåå°ææ¯ï¼ï¼çæä¸ä¸ªå®ç°äºä»£çæ¥å£çå¨æ代çç±»ï¼åèç ï¼ï¼åéè¿åå°æºå¶è·å¾å¨æ代çç±»çæé å½æ°ï¼å©ç¨æé å½æ°çæå¨æ代çç±»çå®ä¾å¯¹è±¡ï¼å¨è°ç¨å ·ä½æ¹æ³åè°ç¨invokeHandleræ¹æ³æ¥å¤çã