徹底搞懂Spring的Bean加載
一、Bean 加載原理
加載過(guò)程: 通過(guò) ResourceLoader和其子類(lèi)DefaultResourceLoader完成資源文件位置定位,實(shí)現(xiàn)從類(lèi)路徑,文件系統(tǒng),url等方式定位功能,完成定位后得到Resource對(duì)象,再交給BeanDefinitionReader,它再委托給
BeanDefinitionParserDelegate完成bean的解析并得到BeanDefinition對(duì)象,然后通過(guò)registerBeanDefinition方法進(jìn)行注冊(cè),IOC容器內(nèi)ibu維護(hù)了一個(gè)HashMap來(lái)保存該BeanDefinition對(duì)象,Spring中的BeanDefinition其實(shí)就是我們用的JavaBean。
什么是BeanDefinition對(duì)象
BeanDefinition是一個(gè)接口,描述了一個(gè)bean實(shí)例,它具有屬性值,構(gòu)造函數(shù)參數(shù)值以及具體實(shí)現(xiàn)提供的更多信息。
在開(kāi)始之前需要認(rèn)真閱讀和理解這個(gè)過(guò)程,有了這個(gè)過(guò)程,閱讀源碼難度就小了一半。
大多源碼都進(jìn)行了注釋?zhuān)械氖枪俜接⑽淖⑨尅?/p>
二、bean.xml
一個(gè)普通的bean配置文件,這里我要強(qiáng)調(diào)的是它里面的格式,因?yàn)榻馕鰳?biāo)簽的時(shí)候會(huì)用到。它有<beans>``<bean>``<import>``<alias>等標(biāo)簽,下文會(huì)對(duì)他們進(jìn)行解析并翻譯成BeanDefinition對(duì)象。
<beans>
<!-- this definition could be inside one beanRefFactory.xml file -->
<bean id="a.qualified.name.of.some.sort"
class="org.springframework.context.support.ClassPathXmlApplicationContext">
<property name="configLocation" value="org/springframework/web/context/beans1.xml"/>
</bean>
<!-- while the following two could be inside another, also on the classpath,
perhaps coming from another component jar -->
<bean id="another.qualified.name"
class="org.springframework.context.support.ClassPathXmlApplicationContext">
<property name="configLocation" value="org/springframework/web/context/beans1.xml"/>
<property name="parent" ref="a.qualified.name.of.some.sort"/>
</bean>
<alias name="another.qualified.name" alias="a.qualified.name.which.is.an.alias"/>
</beans>
三、ResourceLoader.java
加載資源的策略接口(策略模式)。
DefaultResourceLoader is a standalone implementation that is usable outside an ApplicationContext, also used by ResourceEditorAn ApplicationContext is required to provide this functionality, plus extended ResourcePatternResolver support.
public interface ResourceLoader {
/** Pseudo URL prefix for loading from the class path: "classpath:". */
String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;
// 返回一個(gè)Resource 對(duì)象 (明確配置文件位置的對(duì)象)
Resource getResource(String location);
// 返回ResourceLoader的ClassLoader
@Nullable
ClassLoader getClassLoader();
}
然后我們看看DefaultResourceLoader對(duì)于getResource()方法的實(shí)現(xiàn)。
public Resource getResource(String location) {
Assert.notNull(location, "Location must not be null");
for (ProtocolResolver protocolResolver : this.protocolResolvers) {
Resource resource = protocolResolver.resolve(location, this);
if (resource != null) {
return resource;
}
}
// 如果location 以 / 開(kāi)頭
if (location.startsWith("/")) {
return getResourceByPath(location);
}
// 如果location 以classpath: 開(kāi)頭
else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
}
else {
try {
// Try to parse the location as a URL...
URL url = new URL(location);
return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
}
catch (MalformedURLException ex) {
// No URL -> resolve as resource path.
return getResourceByPath(location);
}
}
}
可以看到,它判斷了三種情況:/ classpath: url格式匹配, 然后調(diào)用相對(duì)應(yīng)的處理方法,我只分析classpath:,因?yàn)檫@是最常用的。所以看一看ClassPathResource實(shí)現(xiàn):
public ClassPathResource(String path, @Nullable ClassLoader classLoader) {
Assert.notNull(path, "Path must not be null");
String pathToUse = StringUtils.cleanPath(path);
if (pathToUse.startsWith("/")) {
pathToUse = pathToUse.substring(1);
}
this.path = pathToUse;
this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
}
看了上面的代碼,意味著你配置靜態(tài)資源文件路徑的時(shí)候,不用糾結(jié)classpath:后面用不用寫(xiě)/,因?yàn)槿绻麑?xiě)了它會(huì)給你過(guò)濾掉。
那url如何定位的呢?
跟蹤getResourceByPath(location)方法:
@Override
protected Resource getResourceByPath(String path) {
if (path.startsWith("/")) {
path = path.substring(1);
}
// 這里使用文件系統(tǒng)資源對(duì)象來(lái)定義bean文件
return new FileSystemResource(path);
}
好了,很明顯…跑偏了,因?yàn)槲覀兿胍氖莤ml文件及路徑的解析,不過(guò)還好,換湯不換藥。下文中會(huì)涉及到。
觸發(fā)bean加載
回到正題,我們?cè)谑褂胹pring手動(dòng)加載bean.xml的時(shí)候,用到:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
那就從ClassPathXmlApplicationContext開(kāi)始:
四、ClassPathXmlApplicationContext.java
這個(gè)類(lèi)里面只有構(gòu)造方法(多個(gè))和一個(gè)getConfigResources()方法,構(gòu)造方法最終都統(tǒng)一打到下面這個(gè)構(gòu)造方法中(Spring源碼經(jīng)常這樣,適配器模式):
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
// 動(dòng)態(tài)的確定用哪個(gè)加載器去加載 配置文件
1.super(parent);
// 告訴讀取器 配置文件在哪里, 定位加載配置文件
2.setConfigLocations(configLocations);
// 刷新
if (refresh) {
// 在創(chuàng)建IOC容器前,如果容器已經(jīng)存在,則需要把已有的容器摧毀和關(guān)閉,以保證refresh
//之后使用的是新的IOC容器
3.refresh();
}
}
注意: 這個(gè)類(lèi)非常關(guān)鍵,我認(rèn)為它定義了一個(gè)xml加載bean的一個(gè)Life Cycle:
- super() 方法完成類(lèi)加載器的指定。
- setConfigLocations(configLocations);方法對(duì)配置文件進(jìn)行定位和解析,拿到Resource對(duì)象。
- refresh();方法對(duì)標(biāo)簽進(jìn)行解析拿到BeanDefition對(duì)象,在通過(guò)校驗(yàn)后將其注冊(cè)到IOC容器。(主要研究該方法)
我標(biāo)記的1. 2. 3. 對(duì)應(yīng)后面的方法x, 方便閱讀。
先深入了解下setConfigLocations(configLocations);方法:
方法2. setConfigLocations()
// 解析Bean定義資源文件的路徑,處理多個(gè)資源文件字符串?dāng)?shù)組
public void setConfigLocations(@Nullable String... locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
// resolvePath 為同一個(gè)類(lèi)中將字符串解析為路徑的方法
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}
然后我們繼續(xù)上面看ClassPathXmlApplicationContext的refresh()方法:
方法3. refresh()
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 為refresh 準(zhǔn)備上下文
prepareRefresh();
// 通知子類(lèi)去刷新 Bean工廠
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 用該 上下文來(lái) 準(zhǔn)備bean工廠
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
**注:**下面的方法全都是圍繞refresh()里深入閱讀,該方法套的很深,下面的閱讀可能會(huì)引起不適。
然后看看refresh()方法中的obtainFreshBeanFactory()方法。
方法3.1 obtainFreshBeanFactory()
// 調(diào)用--刷新bean工廠
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 委派模式:父類(lèi)定義了refreshBeanFactory方法,具體實(shí)現(xiàn)調(diào)用子類(lèi)容器
refreshBeanFactory();
return getBeanFactory();
}
然后看obtainFreshBeanFactory()的 refreshBeanFactory()方法。
方法3.1.1 refreshBeanFactory()
// 刷新bean工廠
protected final void refreshBeanFactory() throws BeansException {
// 如果存在容器,就先銷(xiāo)毀并關(guān)閉
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 創(chuàng)建IOC容器
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
// 對(duì)容器進(jìn)行初始化
customizeBeanFactory(beanFactory);
// 調(diào)用載入Bean定義的方法,(使用了委派模式)
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
然后再跟進(jìn)refreshBeanFactory() 的loadBeanDefinitions()方法。
方法3.1.1.1 loadBeanDefinitions()
通過(guò) XmlBeanDefinitionReader 加載 BeanDefinition。
// 通過(guò) XmlBeanDefinitionReader 加載 BeanDefinition
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
// 為beanFactory 創(chuàng)建一個(gè)新的 XmlBeanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
// 為 Bean讀取器設(shè)置Spring資源加載器 (因?yàn)樽娓割?lèi)是ResourceLoader的子類(lèi),所以也是ResourceLoader)
beanDefinitionReader.setResourceLoader(this);
// 為 Bean讀取器設(shè)置SAX xml解析器DOM4J
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
// 初始化 BeanDefinition讀取器
initBeanDefinitionReader(beanDefinitionReader);
// 真正加載 bean定義
loadBeanDefinitions(beanDefinitionReader);
}
再跟進(jìn)loadBeanDefinitions(DefaultListableBeanFactory beanFactory)方法中的loadBeanDefinitions(XmlBeanDefinitionReader reader)方法。
方法3.1.1.1.1 loadBeanDefinitions()
XMLBean讀取器加載BeanDefinition 資源。
// XMLBean讀取器加載Bean 定義資源
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
// 獲取Bean定義資源的定位
Resource[] configResources = getConfigResources();
if (configResources != null) {
// XMLBean讀取器調(diào)用其父類(lèi) AbstractBeanDefinitionReader 讀取定位的Bean定義資源
reader.loadBeanDefinitions(configResources);
}
// 如果子類(lèi)中獲取的bean定義資源定位為空,
// 則獲取 FileSystemXmlApplicationContext構(gòu)造方法中 setConfigLocations 方法設(shè)置的資源
String[] configLocations = getConfigLocations();
if (configLocations != null) {
// XMLBean讀取器調(diào)用其父類(lèi) AbstractBeanDefinitionReader 讀取定位的Bean定義資源
reader.loadBeanDefinitions(configLocations);
}
}
@Override
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int count = 0;
//
for (Resource resource : resources) {
count += loadBeanDefinitions(resource);
}
return count;
}
再跟下去loadBeanDefinitions(): 這只是一個(gè)抽象方法,找到XmlBeanDefinitionReader子類(lèi)的實(shí)現(xiàn):
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
再深入loadBeanDefinitions:
通過(guò)明確的xml文件加載bean
// 通過(guò)明確的xml文件加載bean
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
// 將資源文件轉(zhuǎn)為InputStream的IO流
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
// 從流中獲取 xml解析資源
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
// 設(shè)置編碼
inputSource.setEncoding(encodedResource.getEncoding());
}
// 具體的讀取過(guò)程
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
再深入到doLoadBeanDefinitions():
真正開(kāi)始加載 BeanDefinitions。
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 將xml 文件轉(zhuǎn)換為DOM對(duì)象
Document doc = doLoadDocument(inputSource, resource);
// 對(duì)bean定義解析的過(guò)程,該過(guò)程會(huì)用到 Spring的bean配置規(guī)則
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
... ... ..
}
doLoadDocument()方法將流進(jìn)行解析,返回一個(gè)Document對(duì)象:return builder.parse(inputSource);為了避免擾亂思路,這里的深入自己去完成。
還需要再深入到:registerBeanDefinitions()。
注冊(cè) BeanDefinitions。
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// 得到容器中注冊(cè)的bean數(shù)量
int countBefore = getRegistry().getBeanDefinitionCount();
// 解析過(guò)程入口,這里使用了委派模式
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
// 統(tǒng)計(jì)解析的bean數(shù)量
return getRegistry().getBeanDefinitionCount() - countBefore;
}
再深入registerBeanDefinitions()方法(該方法是委派模式的結(jié)果):
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
// 獲得XML描述符
this.readerContext = readerContext;
doRegisterBeanDefinitions(doc.getDocumentElement());
}
再深入doRegisterBeanDefinitions(doc.getDocumentElement());:
真正開(kāi)始注冊(cè) BeanDefinitions :
protected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
// We cannot use Profiles.of(...) since profile expressions are not supported
// in XML config. See SPR-12458 for details.
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
// 在bean解析定義之前,進(jìn)行自定義解析,看是否是用戶(hù)自定義標(biāo)簽
preProcessXml(root);
// 開(kāi)始進(jìn)行解析bean定義的document對(duì)象
parseBeanDefinitions(root, this.delegate);
// 解析bean定義之后,進(jìn)行自定義的解析,增加解析過(guò)程的可擴(kuò)展性
postProcessXml(root);
this.delegate = parent;
}
接下來(lái)看parseBeanDefinitions(root, this.delegate)。
document的根元素開(kāi)始進(jìn)行解析翻譯成BeanDefinitions。
// 從document的根元素開(kāi)始進(jìn)行解析翻譯成BeanDefinitions
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
// bean定義的document對(duì)象使用了spring默認(rèn)的xml命名空間
if (delegate.isDefaultNamespace(root)) {
// 獲取bean定義的document對(duì)象根元素的所有字節(jié)點(diǎn)
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
// 獲得document節(jié)點(diǎn)是xml元素節(jié)點(diǎn)
if (node instanceof Element) {
Element ele = (Element) node;
// bean定義的document的元素節(jié)點(diǎn)使用的是spring默認(rèn)的xml命名空間
if (delegate.isDefaultNamespace(ele)) {
// 使用spring的bean規(guī)則解析元素 節(jié)點(diǎn)
parseDefaultElement(ele, delegate);
}
else {
// 沒(méi)有使用spring默認(rèn)的xml命名空間,則使用用戶(hù)自定義的解析規(guī)則解析元素節(jié)點(diǎn)
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
// 解析 <import> 標(biāo)簽元素,并進(jìn)行導(dǎo)入解析
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
// alias
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
// bean
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
// beans
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
importBeanDefinitionResource(ele);``processAliasRegistration(ele);``processBeanDefinition(ele, delegate);這三個(gè)方法里分別展示了標(biāo)簽解析的詳細(xì)過(guò)程。
這下看到了,它其實(shí)使用DOM4J來(lái)解析import bean alias等標(biāo)簽,然后遞歸標(biāo)簽內(nèi)部直到拿到所有屬性并封裝到BeanDefition對(duì)象中。比如說(shuō)processBeanDefinition方法。
給我一個(gè)element 解析成 BeanDefinition。
// 給我一個(gè)element 解析成 BeanDefinition
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 真正解析過(guò)程
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
// 注冊(cè): 將db注冊(cè)到ioc,委托模式
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
繼續(xù)深入registerBeanDefinition()。
注冊(cè)BeanDefinitions 到 bean 工廠。
// 注冊(cè)BeanDefinitions 到 bean 工廠
// definitionHolder : bean定義,包含了 name和aliases
// registry: 注冊(cè)到的bean工廠
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
// 真正注冊(cè)
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
再深入registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())。
注冊(cè)BeanDefinitions 到IOC容器。
注意:該方法所在類(lèi)是接口,我們查看的是DefaultListableBeanFactory.java所實(shí)現(xiàn)的該方法。
// 實(shí)現(xiàn)BeanDefinitionRegistry接口,注冊(cè)BeanDefinitions
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
// 校驗(yàn)是否是 AbstractBeanDefinition)
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
// 標(biāo)記 beanDefinition 生效
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
// 判斷beanDefinitionMap 里是否已經(jīng)有這個(gè)bean
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
//如果沒(méi)有這個(gè)bean
if (existingDefinition != null) {
//如果不允許bd 覆蓋已注冊(cè)的bean, 就拋出異常
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
// 如果允許覆蓋, 則同名的bean, 注冊(cè)的覆蓋先注冊(cè)的
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
// 注冊(cè)到容器,beanDefinitionMap 就是個(gè)容器
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
這個(gè)方法中對(duì)所需要加載的bean進(jìn)行校驗(yàn),沒(méi)有問(wèn)題的話就put到beanDefinitionMap中,beanDefinitionMap其實(shí)就是IOC.這樣我們的Bean就被加載到IOC容器中了。