1.Springä¹FactoryBean
2.è¯·ä½ è°è°å¯¹springçç解?
3.Spring源码-09-Bean工厂之getBean方法
4.Spring ä¸ ä¸ªgetBean çä½ç¨
5.Spring IoC:getBean 详解
Springä¹FactoryBean
ä¸è¬æ åµä¸ï¼Spring éè¿åå°æºå¶å©ç¨bean ç classå±æ§æå®å®ç°ç±»æ¥å®ä¾åbeanãå¨æäºæ åµä¸ï¼å®ä¾å bean çè¿ç¨ä¸å«å¤æï¼å¦ææç §ä¼ ç»çæ¹å¼ï¼åéè¦å¨ <bean> ä¸æä¾å¤§éçé 置信æ¯ï¼é ç½®ççµæ´»åº¦åéï¼è¿æ¶åéç¨ç¼ç çæ¹å¼å¯è½ä¼å¾å°ä¸ä¸ªç®åçæ¹æ³ãSpringæä¾äºä¸ä¸ªorg.springframework.bean.FactoryBeançå·¥åæ¥å£ï¼ç¨æ·å¯ä»¥éè¿å®ç°è¯¥æ¥å£å®å¶å®ä¾åçbeanãFactoryBeanæ¥å£å¯¹äºSpringæ¡æ¶æ¥è¯´å ç¨éè¦çå°ä½ï¼Springæ¬èº«å°±æä¾äºç¹å«å¤çFactoryBeançå®ç°ãå®ä»¬éèäºå®ä¾åå¤æbeançç»èï¼ç»ä¸å±åºç¨å¸¦æ¥äºä¾¿å©ãFactoryBeançæºç å¦ä¸ï¼
å¨è¯¥æ¥å£ä¸å®ä¹äºä¸ä¸ªæ¹æ³ï¼
å½é ç½®æä»¶ä¸ <bean> çclasså±æ§é ç½®å®ç°çæ¯FactoryBeanæ¶ï¼éè¿getBean()æ¹æ³è¿åçä¸æ¯ FactoryBean æ¬èº«ï¼èæ¯ FactoryBean ç getObject() æ¹æ³è¿åç对象ã
ä¾å¦ä½¿ç¨ä¼ ç»çæ¹å¼é ç½®ä¸é¢çStudentç <bean> çæ¶ï¼Studentçæ¯ä¸ä¸ªå±æ§é½ä¼å¯¹åºä¸ä¸ª <property> å ç´ çæ ç¾ã
å¦æ使ç¨FactoryBeançæ¹å¼å®ç°å°±æ´çµæ´»ä¸äºï¼éè¿ä¸é¢çéå·åé符çæ¹å¼ä¸æ¬¡æ§å°ä¸ºStudentçææå±æ§æå®é ç½®å¼ï¼
æäºè¿ä¸ä¸ªStudentFactoryBeanåï¼å°±å¯ä»¥å¨é ç½®æ件ä¸ä½¿ç¨ä¸é¢çè¿ç§æ¹æ³é ç½®StudentBeanäºã
å½è°ç¨ getBean("student") æ¶ï¼Springéè¿åå°æºå¶åç° StudentFactoryBean#getObject() æ¹æ³çè¿åãå¦æå¸æè·å StudentFactoryBean çå®ä¾ï¼åéè¦ä½¿ç¨ getBean(beanName) æ¹æ³æ¶å¨beanNameåæ¾ç¤ºçå ä¸ "&" åç¼ï¼ä¾å¦ getBean("&student") ã
è¯·ä½ è°è°å¯¹springçç解?
1.解éspringçioc? å ç§æ³¨å ¥ä¾èµçæ¹å¼ï¼springçä¼ç¹ï¼
IOCä½ å°±è®¤ä¸ºä»æ¯ä¸ä¸ªç产å管çbeanç容å¨å°±è¡äºï¼åæ¥éè¦å¨è°ç¨ç±»ä¸newçä¸è¥¿ï¼ç°å¨é½æ¯æè¿ä¸ªIOC容å¨è¿è¡äº§çï¼å
æ¶ï¼è¦æ¯äº§ççæ¯åä¾çbeanï¼ä»è¿å¯ä»¥ç»ç®¡çbeanççå½å¨æï¼
springçIOCæä¸ç§æ³¨å ¥æ¹å¼ ï¼
第ä¸æ¯æ ¹æ®å±æ§æ³¨å ¥ ä¹å«setæ¹æ³æ³¨å ¥ï¼
第äºç§æ¯æ ¹æ®æé æ¹æ³è¿è¡æ³¨å ¥ï¼
第ä¸ç§æ¯æ ¹æ®æ³¨è§£è¿è¡æ³¨å ¥ï¼è¿ç§æ¹å¼æ认为æ¯è¾å¥½ï¼æ¹ä¾¿ï¼è¦æ¯beanå¤çè¯ï¼ä½¿ç¨å两ç§æ¹å¼ä¼ä½¿å¾é ç½®æ件è¿äºèè¿ã
Springçä¼ç¹ï¼ä¸»è¦æ¯æ ¹æ®å®çIOCåAOPä½ç°çãææè§ä»å°±æ¯ææ们以åç¨å°çå·¥å模å¼å代ç模å¼è¿è¡äºä¸ä¸ªå°è£ ã
IOC主è¦æ¯è§£å³äºä»£ç çè¦åæ§é®é¢ï¼èAOPæ¯é¢ååé¢ç¼ç¨çæ好解éï¼
2.解éSpringä¸IOC, DI, AOP
iocå°±æ¯æ§å¶ç¿»è½¬ææ¯ä¾èµæ³¨å ¥ãéä¿ç讲就æ¯å¦æå¨ä»ä¹å°æ¹éè¦ä¸ä¸ªå¯¹è±¡ï¼ä½ èªå·±ä¸ç¨å»éè¿new çæä½ éè¦ç对象ï¼
èæ¯éè¿springçbeanå·¥åä¸ºä½ é¿çè¿æ ·ä¸ä¸ªå¯¹è±¡ã
aopå°±æ¯é¢ååé¢çç¼ç¨ãæ¯å¦è¯´ä½ æ¯åä¸æ¬¡å¯¹æ°æ®åºæä½ï¼é½è¦çæä¸å¥æ¥å¿ãå¦æï¼ä½ 对æ°æ®åºçæä½æå¾å¤ç±»ï¼
é£ä½ æ¯ä¸ç±»ä¸é½è¦åå ³äºæ¥å¿çæ¹æ³ãä½æ¯å¦æä½ ç¨aopï¼é£ä¹ä½ å¯ä»¥åä¸ä¸ªæ¹æ³ï¼å¨è¿ä¸ªæ¹æ³ä¸æå ³äºæ°æ®åºæä½çæ¹æ³ï¼
æ¯ä¸æ¬¡è°ç¨è¿ä¸ªæ¹æ³çæ¶åï¼å°±å ä¸çææ¥å¿çæä½ã
3.springçioc/aop/代ç
iocæ¯æ§å¶å转ï¼æ¯springçæ ¸å¿ææ³ãéè¿é¢åæ¥å£ç¼ç¨æ¥å®ç°å¯¹ä¸å¡ç»ä»¶çå¨æä¾èµã aopæ¯é¢å
åé¢ç¼ç¨ï¼å®å¹¶ä¸æ¯åªå¨springæè javaä¸ææçï¼å®åé¢å对象ç¼ç¨ï¼oopï¼æ¯ç¸å¯¹èè¨çå¦ä¸ç§ç¼ç¨ææ³ã
springå¨å®ç°aopç¼ç¨æ¶å©ç¨çæ¯javaç代çæºå¶ã 个人è§å¾java代çæºå¶ççæ¯å¾ç¥å¥ãæ ¸å¿å 容并ä¸å¤
4.springçiocæ¯è§£è¦,aopæ¯å¹²ä»ä¹ç
AOPé¢ååé¢ç¼ç¨ å°ç¨åºä¸ç交åä¸å¡é»è¾ï¼æ¯å¦å®å ¨ï¼æ¥å¿ï¼äºå¡çï¼ï¼å°è£ æä¸ä¸ªåé¢ï¼ç¶åæ³¨å ¥å°ç®æ 对象ï¼å ·ä½ä¸å¡é»è¾ï¼ä¸å»ã
æ¯å¦ï¼ å¾å¤æ¹æ³å¯è½ä¼æå¼å¸¸ï¼ä½ è¦è®°å½è¿ä¸ªå¼å¸¸å°æ¥å¿ä¸å»ï¼å¯ä»¥å个æ¦æªå¨ç±»ï¼å¨è¿ä¸ªç±»ä¸è®°å½æ¥å¿ï¼
å¨spring.xmlä¸é ç½®ä¸ä¸ªå¯¹è¿äºè¦è®°å½æ¥å¿çæ¹æ³çaopæ¦æªå¨ å¨è¿ä¸ªæ¹æ³æ§è¡åè°ç¨è¿ä¸ªæ¦æªå¨ï¼è®°å½æ¥å¿ã
è¿æ ·å°±ä¸ç¨æ¯æ¬¡æå¼å¸¸é½è¦æå¨è®°å½æ¥å¿ã springçäºå¡ç®¡çç¨å°çå°±æ¯aop è¿æ ·ä¹å¯ä»¥æé«ç¨åºçå èæ§ã
5.讲解ä¸ä¸Javaä¸Springä¸IOCåAOP
IoCï¼è¯´ç´ç½ç¹ï¼å°±æ¯éè¿é ç½®æ件ï¼XMLæ.propertiesï¼æå®éè¦å®ä¾åçJAVAç±»ï¼ç±»åçå®æ´å符串ï¼ï¼
å æ¬è¯¥JAVAç±»çä¸ç»åå§åå¼ï¼ç¶åæ们å¨ä»£ç ä¸å 载该é ç½®æ件ï¼ç¶åéè¿ .getBean() å½æ°å°±å¯ä»¥å¾å°ä¸ä¸ªè¯¥JAVAç±»ç对象ï¼
并ä¸è¯¥å¯¹è±¡å·²ç»æ ¹æ®é ç½®æ件ä¸æå®çå±æ§å¼è¿è¡äºåå§åã
AOPï¼è¿ä¸ªæ¯IoCæ´ç®åï¼ç´ç½ç¹è¯´å°±æ¯å®ç°è°ç¨æ个æ¹æ³ä¹åæ/åä¹åï¼èªå¨æ§è¡ä¸ç³»åèªå®ä¹çè¯å¥
6.ç®è¿°Springæ¡æ¶ä¸IOCåAOP
IOCï¼æ§å¶å转ï¼æ¯ä¸ç§è®¾è®¡æ¨¡å¼ãä¸å±å«ä¹æ¯æ§å¶æç转移ï¼ç±ä¼ ç»çå¨ç¨åºä¸æ§å¶ä¾èµè½¬ç§»å°ç±å®¹å¨æ¥æ§å¶ï¼
第äºå±æ¯ä¾èµæ³¨å ¥ï¼å°ç¸äºä¾èµç对象å离ï¼å¨springé ç½®æ件ä¸æè¿°ä»ä»¬çä¾èµå ³ç³»ãä»ä»¬çä¾èµå ³ç³»åªå¨ä½¿ç¨çæ¶åæ建ç«ã
AOPï¼é¢ååé¢ï¼æ¯ä¸ç§ç¼ç¨ææ³ï¼OOPç延ç»ãå°ç³»ç»ä¸éæ ¸å¿çä¸å¡æååºæ¥ï¼è¿è¡åç¬å¤çãæ¯å¦äºå¡ãæ¥å¿åå®å ¨çã
Spring çAOPåIOCé½æ¯ä¸ºäºè§£å³ç³»ç»ä»£ç è¦å度è¿é«çé®é¢ã使代ç éç¨åº¦é«ãæäºç»´æ¤ã
ä¸è¿AOPåIOC并ä¸æ¯springä¸ç¹æçï¼åªæ¯springæä»ä»¬åºç¨çæ´çµæ´»æ¹ä¾¿ ã
Spring源码--Bean工厂之getBean方法
Bean实例化与管理是Spring框架的核心功能之一,其中getBean方法作为获取Bean实例的主要手段,具有重要意义。接下来,我们将深入探讨getBean方法及其相关实现,以期更好地理解Spring Bean工厂的资料收集网站源码工作机制。
一、getBean方法
getBean方法是Spring容器对外提供的一种接口,用于根据指定的Bean名称获取对应Bean实例。该方法会根据配置信息和缓存机制,找到并返回所需的Bean。
二、doGetBean方法
doGetBean方法是getBean方法的内部实现,负责处理Bean的查找、创建和返回工作。其流程分为以下几个关键步骤:
1. getSingleton
若Bean是单例且已存在,则直接返回缓存的实例,无需重新创建。
2. createBean
若非单例或未找到缓存实例,传图系统源码将进入创建Bean的流程。此过程涉及实例化、属性填充和初始化三个主要步骤。
2.1 实例化
通过调用对应的构造函数或使用默认构造函数创建Bean实例。
2.2 三级缓存
在实例化后,新创建的Bean会首先存储于缓存中,随后被添加到Bean作用域的缓存中,以备后续使用。
2.3 属性填充
通过依赖注入或属性设置方法填充Bean的属性值,确保其具有所需的功能。
2.4 初始化
执行Bean的初始化方法,实现任何特定的初始化逻辑,如配置文件加载或数据库连接等。
三、流程图
为了更直观地展示getBean方法的执行流程,以下流程图详细展示了从查找至返回Bean实例的全过程,包括缓存操作、实例化、牛排可溯源码属性填充和初始化等关键步骤。
四、循环依赖示意图
在处理循环依赖时,Spring容器会采取特定策略以避免无限循环。以下示意图展示了两个单例Bean(A和B)之间循环依赖的处理过程,以及Spring如何通过延迟初始化等机制解决这一问题。
本文通过深入剖析getBean方法及其相关实现,旨在帮助开发者更好地理解Spring Bean工厂的工作机制。通过掌握这些关键概念与流程,可以更高效地利用Spring框架构建可维护且高性能的应用程序。
Spring ä¸ ä¸ªgetBean çä½ç¨
getBeanæ¯ç¨æ¥è·åapplicationContext.xmlæ件ébeançï¼ï¼ï¼åçæ¯beançidãä¸ç§æ¯singletonï¼ä¸ç§æ¯prototypeï¼é»è®¤çæ¯singletonï¼è¿ç§å®ä¹çbeanå®ä¾çä½ç¨æ¯ä¸springç容å¨ä¸è´çï¼åªæspring容å¨åå§åï¼è°ç¨getBeanå¾å°çsingletonå®ä¾å§ç»æ¯åä¸ä¸ªbeançå®ä¾springå®ä¹çbeanæ两ç§ä½ç¨èå´ï¼æ¯æ¯å½è°ç¨getBeanå¾å°å®ä¾çæ¶åspringé½ä¼newä¸ä¸ªå®ä¾æ¥ç»ä½ ï¼èprototypeçå®ä¾ã
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 的内容。
推荐阅读
2024-11-23 03:01
2024-11-23 02:48
2024-11-23 02:08
2024-11-23 01:47
2024-11-23 01:36
2024-11-23 01:24
2024-11-23 01:20
2024-11-23 01:08