1.Linux ioctl及ioctl command
2.Spring IoC源码深度剖析
3.Spring源码系列-BeanPostProcessor与BeanFactoryPostProcessor
4.springçç»ä»¶åä½ç¨(springclouç»ä»¶)
5.Spring源码- 02 Spring IoC容器启动之refresh方法
6.Spring IoC:getBean 详解
Linux ioctl及ioctl command
在Linux驱动开发中,open、read、write等函数是常用的操作设备的手段,但除此之外,ioctl函数的qbasic的源码重要性不容忽视。它允许用户程序根据自身需求定制硬件行为,如调整波特率或获取设备信息。ioctl是用户空间与内核驱动直接交互的关键途径,尽管如此,它也存在一些局限性。
ioctl操作分为用户层和内核两部分。用户层主要通过ioctl系统调用来控制设备参数,man手册提供了函数原型。该函数作用于特殊文件的底层设备参数,比如调整字符设备的特性。参数包括文件描述符fd,一个设备依赖的命令代码(旧版本称为ioctl command,现已改名),以及可选的参数,如char *argp,用于传递数据给设备。
驱动程序中,每当使用ioctl操作设备时,实际上是调用file_operations结构的unlocked_ioctl回调函数。每个设备驱动都需要为特定的ioctl命令提供实现,以实现设备与用户空间的交互。
编写ioctl代码前,开发者需要选择一个系统范围内的唯一命令编号。虽然可能有诱惑从0或1开始,但这样会增加错误匹配的风险。命令号通常由位无符号整型组成,分为nr(8位)、安米app源码type(8位)、size(体系结构相关,如或位)和direction(数据传输方向)。内核提供了一些宏如_IOC、_IO、_IOR和_IOW,用于简化命令类型和大小的定义。
Linux内核的ioctl command在5..版本中已分配了部分命令,开发者可以查阅\Documentation\userspace-api\ioctl\ioctl-number.rst获取详细信息。学习Linux内核源码的更多资料,可以参考学习群链接,群内共享了相关的学习资料。
Spring IoC源码深度剖析
Spring IoC容器初始化深度剖析
Spring IoC容器是Spring的核心组件,主要负责对象管理和依赖关系管理。容器体系丰富多样,如BeanFactory作为顶层容器,它定义了所有IoC容器的基本原则,而ApplicationContext及其子类如ClassPathXmlApplicationContext和AnnotationConfigApplicationContext则提供了额外功能。Spring IoC容器的初始化流程关键在AbstractApplicationContext的refresh方法中。 1.1 初始化关键点 通过创建特定类LagouBean并设置断点,我们发现Bean的创建在未设置延迟加载时,发生在容器初始化过程中。构造函数调用、InitializingBean的afterPropertiesSet方法以及BeanFactoryPostProcessor和BeanPostProcessor的初始化和调用,都在refresh方法的不同步骤中发生。 1.2 主体流程概览 Spring IoC容器初始化的主体流程主要集中在AbstractApplicationContext的refresh方法,涉及Bean对象创建、构造函数调用、初始化方法执行和处理器调用等步骤。 1.3 深度剖析 分析发现,延迟加载机制使得懒加载的bean在第一次调用getBean时才进行初始化。而对于非懒加载bean,神马电影新源码它们在容器初始化阶段已经完成并缓存。Spring处理循环依赖的方法依赖于构造器调用的顺序规则,不支持原型bean的循环依赖,而对单例bean则通过setXxx或@Autowired方法提前暴露对象来避免循环依赖。Spring源码系列-BeanPostProcessor与BeanFactoryPostProcessor
在Spring框架中,BeanPostProcessor与BeanFactoryPostProcessor各自承担着不同的职责,它们在IoC容器的工作流程中起着关键作用。
BeanFactoryPostProcessor作用于BeanDefinition阶段,对容器中Bean的定义进行处理。这个过程发生在BeanFactory初始化时,对BeanDefinition进行修改或增强,提供了一种在不修改源代码的情况下定制Bean的机制。相比之下,BeanPostProcessor则在Bean实例化之后生效,对已经创建的Bean对象进行进一步处理或替换,提供了更晚、更灵活的扩展点。
以制造杯子为例,BeanFactoryPostProcessor相当于在选择材料和形状阶段进行定制,而BeanPostProcessor则在杯子制造完成后,进行诸如加花纹、抛光等深加工。
在Spring框架中,BeanPostProcessor的使用场景较为广泛,尤其在实现AOP(面向切面编程)时,通过使用代理类替换原始Bean,实现如日志记录、事务管理等功能。
此外,容器在启动后,还会进行消息源初始化、广播器初始化及监听器初始化,成人直播系统源码为Bean实例化做好准备。完成这些准备工作后,容器会调用registerBeanPostProcessors方法注册BeanPostProcessor,对已创建的Bean进行进一步处理。同时,初始化消息源、广播器和监听器,为后续事件处理做好基础。
总结,BeanFactoryPostProcessor与BeanPostProcessor在Spring IoC容器中的作用各有侧重。前者侧重于对BeanDefinition的定制,后者则是在Bean实例化后的进一步加工,两者共同为构建灵活、可扩展的IoC容器提供了强大的支持。
在深入分析Spring框架的源码时,我们发现refresh()方法的实现中包含了对BeanFactoryPostProcessor和BeanPostProcessor的注册与处理。这些处理步骤确保了容器能够在启动时对Bean进行正确的配置和初始化。
文章中通过一个例子展示了如何使用BeanFactoryPostProcessor替换已注册Bean的实现,以及对其源码的分析。通过例子和源码的结合,读者能够更直观地理解这些后置处理器在Spring框架中的应用和工作原理。
springçç»ä»¶åä½ç¨(springclouç»ä»¶)
ç®è¦è¯´æspringçä¸¤ä¸ªæ ¸å¿åè½åå ¶ä½ç¨
springæ¡æ¶æ¯ä¸ä¸ªè½»é级çå¼æºä»ä¼æ¡æ¶ï¼æ¯ä¸ä¸ªIOCåAOP容å¨ãå®æ¯ä½ä¾µå ¥å¼è®¾è®¡ï¼ç¬ç«äºåç§åºç¨æå¡å¨ï¼
ä¾èµæ³¨å ¥çç¹ç¹å°ç»ä»¶å ³ç³»éæåï¼éä½è¦å度
æ§å¶å转ï¼IOCï¼ï¼ç¨æ¥éä½ç¨åºä»£ç ä¹é´çè¦å度ï¼ä½¿æ´ä¸ªç¨åºä½ç³»ç»ææ´å çµæ´»ï¼åæ¶å°ç±»çå建åä¾èµå ³ç³»åå¨é ç½®æ件éï¼ç±é ç½®æä»¶æ³¨å ¥ï¼è¾¾å°æ¾è¦åçææã
DIï¼ä¾èµæ³¨å ¥ï¼
设å¼æ³¨å ¥ï¼åºå±å®ç°setæ¹æ³èµå¼ã
使ç¨æé å¨æ³¨å ¥ï¼ç½©å³åºå±å®ç°æé æ¹æ³æ³¨å ¥ï¼æ ¹æ®beanä¸çåæ°ç±»åååæ°æ°éï¼å¯»æ¾å¯¹åºçæé æ¹æ³ã
èªå¨è£ é ï¼ä¸è½èªå¨è£ é æè°çç®åç±»åå æ¬åºæ¬ç±»åï¼å符串åéåç±»é常ç¨æ¥èªå¨è£ é 对象
æç §å称æ¥èªå¨è£ é åºå±å®ç°æ¯setæ¹æ³
æç §ç±»åæ¥èªå¨è£ é åºå±å®ç°æ¯setæ¹æ³
2.é¢ååé¢ç¼ç¨ï¼AOPï¼
æ主è¦çä½ç¨ï¼å¯ä»¥å¨ä¸ä¿®æ¹æºä»£ç çæ åµä¸ï¼ç»ç®æ æ¹æ³å¨ææ·»å åè½
ä¸å¡é»è¾å°±ä¸å¿çå¤çå®é éæ±ï¼éç¨çå¢å¼ºåè½ç¬ç«åºæ¥ãå°å®å ¨äºå¡çç¨åºé»è¾ç¸å¯¹ç¬ç«çåè½æ½ååºæ¥ï¼å©ç¨Springçé ç½®æ件å°è¿äºåè½æè¿å»ï¼å®ç°äºæç §åé¢ç¼ç¨ï¼æé«äºå¤ç¨æ§ã
åç§å¢å¼ºæ¹å¼ï¼
åç½®å¢å¼ºï¼å¨æ ¸å¿åè½ä¹åæ§è¡çé¢å¤åè½
åç½®å¢å¼ºï¼å¨æ ¸ç©ææ å¿åè½ä¹åæ§è¡çé¢å¤åè½
å¼å¸¸å¢å¼ºï¼å¨æ ¸å¿åè½åçå¼å¸¸æ¶æ§è¡çé¢å¤åè½
ç¯ç»å¢å¼ºï¼å¨æ ¸å¿åè½ä¹å以åä¹åæ§è¡çé¢å¤åè½
springå å«åªäºç»ä»¶
Springæ¡æ¶æ¯ä¸ä¸ªåå±æ¶æï¼ç±7个å®ä¹è¯å¥½ç模åç»æè¢å¤ãSpring模åæ建å¨æ ¸å¿å®¹å¨ä¹ä¸ï¼æ ¸å¿å®¹å¨ç«å®´å®ä¹äºå建ãé ç½®å管çbeançæ¹å¼ï¼ç»æSpringæ¡æ¶çæ¯ä¸ªæ¨¡åï¼æç»ä»¶ï¼é½å¯ä»¥åç¬åå纤æ¹å¨ï¼æè ä¸å ¶ä»ä¸ä¸ªæå¤ä¸ªæ¨¡åèåå®ç°ã
SpringMVC主è¦ç»ä»¶è¯´æ1ãå端æ§å¶å¨DispatcherServletï¼ä¸éè¦å¼åï¼ç±æ¡æ¶æä¾ãæ ¸å¿ãï¼
DispatcherServletæ¯SpringMVCçå ¥å£å½æ°ãæ¥æ¶è¯·æ±ï¼ååºç»æï¼ç¸å½äºè½¬åå¨ç¢§ç®ï¼ä¸å¤®å¤çå¨ãæäºDispatcherServletï¼å¯ä»¥å¤§å¤§åå°å ¶å®ç»ä»¶ä¹é´çè¦å度ã
ç¨æ·è¯·æ±å°è¾¾å端æ§å¶å¨ï¼å°±ç¸å½äºmvc模å¼ä¸çcï¼DispatcherServletæ¯æ´ä¸ªæµç¨æ§å¶çä¸å¿ï¼ç±å®è°ç¨å ¶å®ç»ä»¶æ¥å¤çç¨æ·ç请æ±ã
2ãå¤çå¨æ å°å¨HandlerMapping(ä¸éè¦å¼åï¼ç±æ¡æ¶æä¾)
HandlerMappingè´è´£æ ¹æ®ç¨æ·è¯·æ±ï¼URLï¼ï¼æ¾å°ç¸åºçHandlerå³å¤çå¨ï¼Controllerï¼ï¼SpringMVCæä¾äºä¸åæ å°å¨å®ç°çä¸åæ å°æ¹å¼ï¼ä¾å¦ï¼é ç½®æ件æ¹å¼ï¼å®ç°æ¥å£æ¹å¼ï¼æ³¨è§£æ¹å¼çã
3ãå¤çå¨éé å¨HandlerAdapter(ä¸éè¦å¼åï¼ç±æ¡æ¶æä¾)
æç §ç¹å®è§åï¼HandlerAdapterè¦æ±çè§åï¼å»æ§è¡Handlerï¼éè¿HandlerAdapter对å¤çå¨è¿è¡æ§è¡ï¼è¿æ¯éé å¨æ¨¡å¼çåºç¨ï¼éè¿æ©å±éé å¨å¯ä»¥å¯¹æ´å¤ç±»åçå¤çå¨è¿è¡å¤çã
4ãå¤çå¨Handler(éè¦å·¥ç¨å¸å¼å)
Handleræ¯ç»§DispatcherServletå端æ§å¶å¨çå端æ§å¶å¨ï¼å¨DispatcherServletçæ§å¶ä¸ï¼Handlerå¯¹å ·ä½çç¨æ·è¯·æ±è¿è¡å¤çãç±äºHandleræ¶åå°å ·ä½çç¨æ·ä¸å¡è¯·æ±ï¼æ以ä¸è¬æ åµä¸éè¦å·¥ç¨å¸æ ¹æ®ä¸å¡éæ±æ¥å¼åHandlerã
5ãè§å¾è§£æå¨ViewResolver(ä¸éè¦å¼åï¼ç±æ¡æ¶æä¾)
ä½ç¨ï¼è¿è¡è§å¾è§£æï¼æ ¹æ®é»è¾è§å¾å解ææçæ£çè§å¾ï¼Viewï¼ï¼ViewResolverè´è´£å°å¤çç»æçæViewè§å¾ãé¦å ï¼æ ¹æ®é»è¾è§å¾å解ææç©çè§å¾åï¼å³å ·ä½ç页é¢å°åï¼ï¼åçæViewè§å¾å¯¹è±¡ï¼æå对Viewè¿è¡æ¸²æï¼å°å¤çç»æéè¿é¡µé¢å±ç¤ºç»ç¨æ·ã
SpringMVCæ¡æ¶æä¾äºå¾å¤çViewè§å¾ç±»åï¼å æ¬ï¼jstlViewãfreemarkerViewãpdfViewçãä¸è¬æ åµä¸ï¼éè¦éè¿é¡µé¢æ ç¾æ页æ¸é®é¢æ¨¡çææ¯ï¼å°æ¨¡åæ°æ®éè¿é¡µé¢å±ç¤ºç»ç¨æ·ï¼è¿éè¦ç±å·¥ç¨å¸æ ¹æ®ä¸æ §å·§ä¸å¡éæ±å¼åå ·ä½ç页é¢ã
6ãè§å¾View(éè¦å·¥ç¨å¸å¼å)
Viewæ¯ä¸ä¸ªæ¥å£ï¼å®ç°ç±»æå¯ä»¥æ¯æä¸åçViewç±»åï¼jspãfreemarkerãpdf...ï¼
æ»ç»ï¼å¤çå¨Handlerï¼ä¹å°±æ¯å¹³å¸¸è¯´çControlleræ§å¶å¨ï¼ä»¥åè§å¾å±Viewï¼é½æ¯éè¦èªè¡å¼åçãå ¶ä»çä¸äºç»ä»¶ï¼å¦ï¼å端æ§å¶å¨DispatcherServletãå¤çå¨æ å°å¨HandlerMappingãå¤çå¨éé å¨HandlerAdapterçé½æ¯ç±æ¡æ¶æä¾ã
spring主è¦çä½ç¨ï¼Springæ¡æ¶æ¯ä¸ºäºè§£å³ä¼ä¸åºç¨å¼åçå¤ææ§èå建çã
Springçç¨éä¸ä» ä» éäºæå¡å¨ç«¯çå¼åãä»ç®åæ§ãå¯æµè¯æ§åæ¾è¦åæ§è§åº¦èè¨ï¼ç»å¤§é¨åJavaåºç¨é½å¯ä»¥ä»Springä¸åçã使ç¨åºæ¬çJavaBean代æ¿EJBï¼å¹¶æä¾äºæ´å¤çä¼ä¸åºç¨åè½ã
æ©å±èµæ
ä¼ç¹
1ãJAVAEEåºè¯¥æ´å 容æ使ç¨ã
2ãé¢å对象ç设计æ¯ä»»ä½å®ç°ææ¯ï¼æ¯å¦JAVAEEï¼é½éè¦ã
3ãé¢åæ¥å£ç¼ç¨ï¼èä¸æ¯é对类ç¼ç¨ãSpringå°ä½¿ç¨æ¥å£çå¤æ度éä½å°é¶ãï¼é¢åæ¥å£ç¼ç¨æåªäºå¤æ度ï¼
4ã代ç åºè¯¥æäºæµè¯ãSpringæ¡æ¶ä¼å¸®å©ä½ ï¼ä½¿ä»£ç çæµè¯å¤è¡¡æ´å ç®åã
5ãJavaBeanæä¾äºåºç¨ç¨åºé ç½®çæ好æ¹æ³ã
6ãå¨Javaä¸ï¼å·²æ£æ¥å¼å¸¸ï¼Checkedexceptionï¼è¢«è¿åº¦ä½¿ç¨ãæ¡æ¶ä¸åºè¯¥è¿«ä½¿ä½ ææ碧è·ä¸æè´ºåè½æ¢å¤çå¼å¸¸ã
åèèµææ¥æºï¼ç¾åº¦ç¾ç§-springæ¡æ¶
Spring源码- Spring IoC容器启动之refresh方法
在注册阶段,AnnotationConfigApplicationContext构造方法中的第一个方法被分析过。接下来,我们关注第二个方法:register(componentClasses)。在使用XML配置方式时,通过new ClassPathXmlApplicationContext("classpath:spring.xml")来创建实例,其中需要指定xml配置文件路径。使用注解方式时,也需要为ApplicationContext提供起始配置源头,这里使用配置类代替xml配置文件,按照配置类中的保修系统网站源码注解(如@ComponentScan、@Import、@Bean)解析并注入Bean到IoC容器。
通过配置类,Spring解析注解实现Bean的注入。使用@Configuration注解定义的配置类相当于xml配置文件,但目前Spring推荐使用注解方式,xml配置的使用概率正在降低。
register(componentClasses)方法的核心逻辑在AnnotatedBeanDefinitionReader#doRegisterBean中,将传入的配置类解析为BeanDefinition并注册到IoC容器。ConfigurationClassPostProcessor这个BeanFactory后置处理器在IoC初始化时,获取配置类的BeanDefinition集合,开始解析。
真正启动IoC容器的流程在refresh()方法中,这是了解IoC容器启动流程的关键步骤。refresh方法在AbstractApplicationContext中定义,采用模板模式,提供IoC初始化流程的基本实现,子类可以扩展。
下面分析refresh()方法的每个步骤,以了解IoC容器的启动流程。
prepareRefresh方法主要在refresh执行前进行准备工作,如设置Context的启动时间、状态,以及扩展系统属性相关。
initPropertySources()方法主要用于扩展配置来源,如网络、物理文件、数据库等加载配置信息。StandardEnvironment默认只提供加载系统变量和应用变量的功能,用于子类扩展。
❝initPropertySources方法常见扩展场景包括:❞
getEnvironment().validateRequiredProperties()确保设置的必要属性在环境中存在,否则抛出异常终止应用。
BeanFactory是Spring的基本IoC容器,ApplicationContext包装了BeanFactory,提供更智能、更便捷的功能。ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();获取的BeanFactory是IoC容器初始化工作的基础。
上面获取的BeanFactory还不能直接使用,需要填充必要的配置信息。至此,IoC容器的启动流程基本完成。
这里对IoC启动流程有个大致、直观的印象。主要步骤包括:准备阶段、配置来源扩展、初始化BeanFactory、填充配置、解析配置类、注册Bean、实例化BeanPostProcessor、初始化国际化和事件机制、以及创建内嵌Servlet容器(在SpringBoot中实现)。这些步骤确保了IoC容器顺利启动并管理Bean。
Spring IoC:getBean 详解
接着 Spring IoC:finishBeanFactoryInitialization 详解,我们正式开始学习获取 bean 实例方法,该方法是 Spring 最核心的方法。
单击 preInstantiateSingletons 方法里的 getBean(beanName) 代码,进入该方法。
见 doGetBean 方法详解。
doGetBean
1.解析 beanName,主要是解析别名、去掉 FactoryBean 的修饰符 “&”,在 Spring IoC:finishBeanFactoryInitialization 详解 中的代码块4已解析过。
2.尝试从缓存中获取 beanName 对应的实例,在 Spring IoC:finishBeanFactoryInitialization 详解 中的代码块7已解析过。
3.1 返回 beanName 对应的实例对象(主要用于 FactoryBean 的特殊处理,普通 bean 会直接返回 sharedInstance 本身),见代码块1详解。
6.如果不是仅仅做类型检测,而是创建 bean 实例,这里要将 beanName 放到 alreadyCreated 缓存,见代码块5详解。
7.根据 beanName 重新获取 MergedBeanDefinition,在 Spring IoC:finishBeanFactoryInitialization 详解 中的代码块2已解析过。
8.2 检查 dep 是否依赖于 beanName,即检查是否存在循环依赖,见代码块6详解。
8.4 将 dep 和 beanName 的依赖关系注册到缓存中,见代码块7详解。
9.1 scope 为 singleton 的 bean 创建(新建了一个 ObjectFactory,并且重写了 getObject 方法),见代码块8详解。
9.1.1、9.2.2、9.3.4 创建 bean 实例,限于篇幅,在下篇文章单独解析。
9.1.2、9.2.4、9.3.6 返回 beanName 对应的实例对象,见代码块1详解。
9.2.1 scope 为 prototype 时创建实例前的操作、9.2.3 scope 为 prototype 时 创建实例后的操作,相对应的两个方法,见代码块详解。
代码块1:getObjectForBeanInstance
如果对 FactoryBean 不熟悉的,可以回头去看 Spring IoC:finishBeanFactoryInitialization 详解 中对 FactoryBean 的简单介绍。
6.mbd 为空,但是该 bean 的 BeanDefinition 在缓存中存在,则获取该 bean 的 MergedBeanDefinition,在 Spring IoC:finishBeanFactoryInitialization 详解 中的代码块2已经解析过。
8.从 FactoryBean 获取对象实例,见代码块2详解。
代码块2:getObjectFromFactoryBean
3.调用 FactoryBean 的 getObject 方法获取对象实例,见代码块3详解。
5.对 bean 实例进行后续处理,执行所有已注册的 BeanPostProcessor 的 postProcessAfterInitialization 方法,见代码块4详解。
代码块3:doGetObjectFromFactoryBean
很简单的方法,就是直接调用 FactoryBean 的 getObject 方法来获取到对象实例。
细心的同学可以发现,该方法是以 do 开头,看过 Spring IoC:源码总览 的同学知道,我在总览里就特别提到以 do 开头的方法是最终进行实际操作的方法,例如本方法就是 FactoryBean 最终实际进行创建 bean 对象实例的方法。
代码块4:postProcessObjectFromFactoryBean
这边走的是 AbstractAutowireCapableBeanFactory 里的方法。通过前面的介绍,我们知道创建的 BeanFactory 为 DefaultListableBeanFactory,而 DefaultListableBeanFactory 继承了 AbstractAutowireCapableBeanFactory,因此这边会走 AbstractAutowireCapableBeanFactory 的重写方法。
在 Spring IoC:registerBeanPostProcessors 详解 中已经学过 BeanPostProcessor,在创建完 bean 实例后,会执行 BeanPostProcessor 的 postProcessAfterInitialization 方法。
代码块5:markBeanAsCreated
2.这边会将 beanName 对应的 MergedBeanDefinition 移除,然后在之后的代码重新获取,主要是为了使用最新的 MergedBeanDefinition 来进行创建操作。
代码块6:isDependent
这边引入了一个缓存 dependentBeanMap:beanName -> 所有依赖 beanName 对应的 bean 的 beanName 集合。内容比较简单,就是检查依赖 beanName 的集合中是否包含 dependentBeanName,隔层依赖也算。例如:A 依赖了 B,B 依赖了 C,则 A 也算依赖了 C。
代码块7:registerDependentBean
这边又引入了一个跟 dependentBeanMap 类似的缓存,dependenciesForBeanMap:beanName -> beanName 对应的 bean 依赖的所有 bean 的 beanName 集合。
这两个缓存很容易搞混,举个简单例子:例如 B 依赖了 A,则 dependentBeanMap 缓存中应该存放一对映射:其中 key 为 A,value 为含有 B 的 Set;而 dependenciesForBeanMap 缓存中也应该存放一对映射:其中 key 为:B,value 为含有 A 的 Set。
代码块8:getSingleton
5.创建单例前的操作,7.创建单例后的操作,这两个方法是对应的,见代码块9详解。
6.执行 singletonFactory 的 getObject 方法获取 bean 实例,该方法会走文章开头 doGetBean 方法的注释 9.1.1。
8.如果是新的单例对象,将 beanName 和对应的单例对象添加到缓存中,见代码块详解。
代码块9:beforeSingletonCreation、afterSingletonCreation
inCreationCheckExclusions 是要在创建检查排除掉的 beanName 集合,正常为空,可以不管。这边主要是引入了 singletonsCurrentlyInCreation 缓存:当前正在创建的 bean 的 beanName 集合。在 beforeSingletonCreation 方法中,通过添加 beanName 到该缓存,可以预防出现构造器循环依赖的情况。
为什么无法解决构造器循环依赖?
我们之前在 Spring IoC:finishBeanFactoryInitialization 详解 中的代码块7提过,getSingleton 方法是解决循环引用的核心代码。解决逻辑的第一句话:“我们先用构造函数创建一个 “不完整” 的 bean 实例”,从这句话可以看出,构造器循环依赖是无法解决的,因为当构造器出现循环依赖,我们连 “不完整” 的 bean 实例都构建不出来。Spring 能解决的循环依赖有:通过 setter 注入的循环依赖、通过属性注入的循环依赖。
代码块:addSingleton
代码块:beforePrototypeCreation、afterPrototypeCreation
该方法和代码块9的两个方法类似。主要是在进行 bean 实例的创建前,将 beanName 添加到 prototypesCurrentlyInCreation 缓存;bean 实例创建后,将 beanName 从 prototypesCurrentlyInCreation 缓存中移除。这边 prototypesCurrentlyInCreation 存放的类型为 Object,在只有一个 beanName 的时候,直接存该 beanName,也就是 String 类型;当有多个 beanName 时,转成 Set 来存放。
总结
本文介绍了获取 bean 实例的大部分内容,包括先从缓存中检查、 FactoryBean 的 bean 创建、实例化自己的依赖(depend-on 属性)、创建 bean 实例的前后一些标记等,在下篇文章中,将解析创建 bean 的内容。
推荐阅读