知識要點:
Spring啟動流程概述
Spring啟動流程詳解
Spring啟動流程概述
Spring的IoC容器在實現(xiàn)控制反轉(zhuǎn)和依賴注入的過程中,可以劃分為兩個階段:
- 容器啟動階段
- Bean實例化階段
容器初始化
- 加載配置
- 分析配置信息
- 將Bean信息裝配到BeanDefinition
- 將Bean信息注冊到相應(yīng)的BeanDefinitionRegistry
- 其他后續(xù)處理
容器實例化
- 根據(jù)策略實例化對象
- 裝配依賴
- Bean初始化前處理
- 對象初始化
- 對象其他處理
- 注冊回調(diào)接口
Spring啟動流程詳解
啟動流程源碼概覽
ClassPathXmlApplicationContext
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
public ClassPathXmlApplicationContext(String[] paths, Class<?> clazz, ApplicationContext parent)
throws BeansException {
super(parent);
Assert.notNull(paths, "Path array must not be null");
Assert.notNull(clazz, "Class argument must not be null");
this.configResources = new Resource[paths.length];
for (int i = 0; i < paths.length; i++) {
this.configResources[i] = new ClassPathResource(paths[i], clazz);
}
refresh();
}
AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException {
// 方法加鎖避免多線程同時刷新Spring上下文
synchronized (this.startupShutdownMonitor) {
// 準備上下文刷新
prepareRefresh();
// 告訴子類刷新內(nèi)部的beanFactory返回新的BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 在當前上下文中準備要beanFactory
prepareBeanFactory(beanFactory);
try {
// 允許在上下文子類中對beanFactory進行后置處理
postProcessBeanFactory(beanFactory);
// 在上下文中將BeanFactory處理器注冊為Bean
invokeBeanFactoryPostProcessors(beanFactory);
// 注冊Bean處理器用于攔截Bean的創(chuàng)建
registerBeanPostProcessors(beanFactory);
// 在上下文中初始化國際化信息
initMessageSource();
// 在上下文中初始化event multicaster(事件多播器)
initApplicationEventMulticaster();
// 在指定的上下文子類中初始化其他指定的beans
onRefresh();
// 檢查并注冊事件監(jiān)聽
registerListeners();
// 實例化所有剩余的(非延遲初始化)單例
finishBeanFactoryInitialization(beanFactory);
// 最后一步:發(fā)布相應(yīng)的事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 如果出現(xiàn)異常則銷毀已創(chuàng)建的單例
destroyBeans();
// 重置活動標志。
cancelRefresh(ex);
// 將異常傳遞給調(diào)用者
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
整個refresh()的代碼都是同步的繁莹,而對應(yīng)的同步對象是startupShutdownMonitor。startupShutdownMonitor只在refresh()和close()兩個方法里被用到,而它是用來同步applicationContext的刷新和銷毀仅乓。
面試題
Spring的registerShutdownHook和close有什么區(qū)別?
當close()
被調(diào)用時會立即關(guān)閉或者停止ApplicationContext匿又;而調(diào)用registerShutdownHook()
將在稍后JVM關(guān)閉時關(guān)閉或停止ApplicationContext方灾,該方法主要通過JVM ShutdownHook
來實現(xiàn)。
ShutdownHook
Java 語言提供一種 ShutdownHook(鉤子)機制碌更,當 JVM 接受到系統(tǒng)的關(guān)閉通知之后裕偿,調(diào)用 ShutdownHook 內(nèi)的方法,用以完成清理操作痛单,從而實現(xiàn)平滑退出應(yīng)用嘿棘。
第一步 刷新準備
protected void prepareRefresh() {
// 設(shè)置啟動時間。當前毫秒數(shù)代表當前applicationContext的創(chuàng)建時間
this.startupDate = System.currentTimeMillis();
// 設(shè)置容器關(guān)閉標志
this.closed.set(false);
// 設(shè)置啟動標志
this.active.set(true);
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
// 初始化屬性資源
initPropertySources();
// 驗證所有的屬性是否都是可解析的
getEnvironment().validateRequiredProperties();
// ApplicationEvent初始化
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
第二步 獲取BeanFactory
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
該方法對BeanFactory進行刷新旭绒。如果刷新前已經(jīng)存在一個BeanFactory則需要先進行關(guān)閉操作鸟妙,而后初始化一個新BeanFactory焦人。
protected final void refreshBeanFactory() throws BeansException {
// 判斷是否已經(jīng)存在一個BeanFactory
if (hasBeanFactory()) {
// 銷毀已經(jīng)存在BeanFactory中的所有Bean
destroyBeans();
// 關(guān)閉BeanFactory
closeBeanFactory();
}
try {
// 創(chuàng)建新的BeanFactory對象(DefaultListableBeanFactory)
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 給BeanFactory設(shè)置Id
beanFactory.setSerializationId(getId());
// 該方法主要對2個標志進行設(shè)置:allowBeanDefinitionOverriding和allowCircularReferences
// allowBeanDefinitionOverriding:是否允許使用相同名稱重新注冊不同的bean(Spring默認true,SpringBoot默認false)
// allowCircularReferences:是否允許循環(huán)依賴
customizeBeanFactory(beanFactory);
// 加載配置文件
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
// 新創(chuàng)建的BeanFactory賦給成員變量beanFactory
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
DefaultSingletonBeanRegistry
// 當前這個單例是否正在被銷毀
// true:表示單例已經(jīng)執(zhí)行了destroy方法重父,或者出現(xiàn)異常時執(zhí)行了destroySingleton方法
private boolean singletonsCurrentlyInDestruction = false;
// 緩存兩個Bean之間的包含關(guān)系花椭。如:一個Bean中包含了一個內(nèi)部Bean。
private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<String, Set<String>>(16);
// 緩存Bean與其他依賴Bean的關(guān)系
private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<String, Set<String>>(64);
// 緩存被依賴Bean與其他依賴Bean的關(guān)系
private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<String, Set<String>>(64);
// 銷毀所有的Bean實例
public void destroySingletons() {
if (logger.isDebugEnabled()) {
logger.debug("Destroying singletons in " + this);
}
synchronized (this.singletonObjects) {
// 設(shè)置銷毀標志
this.singletonsCurrentlyInDestruction = true;
}
// 銷毀disposableBeans緩存中所有單例bean
String[] disposableBeanNames;
synchronized (this.disposableBeans) {
disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
}
for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
destroySingleton(disposableBeanNames[i]);
}
// 清空包含關(guān)系
this.containedBeanMap.clear();
// 清空依賴和被依賴關(guān)系
this.dependentBeanMap.clear();
this.dependenciesForBeanMap.clear();
// 清空緩存
clearSingletonCache();
}
加載配置
AbstractXmlApplicationContext
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
// 以Resource方式加載配置
Resource[] configResources = getConfigResources();
if (configResources != null) {
// 讀取配置文件
reader.loadBeanDefinitions(configResources);
}
// 以String方式加載配置
String[] configLocations = getConfigLocations();
if (configLocations != null) {
// 讀取配置文件
reader.loadBeanDefinitions(configLocations);
}
}
AbstractBeanDefinitionReader
@Override
// 通過String數(shù)組參數(shù)locations加載Bean房午,并返回加載Bean的數(shù)量
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int counter = 0;
for (String location : locations) {
// 加載BeanDefinintion
counter += loadBeanDefinitions(location);
}
// 返回加載Bean的數(shù)量
return counter;
}
@Override
// 通過Resource數(shù)組參數(shù)locations加載Bean矿辽,并返回加載Bean的數(shù)量
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int counter = 0;
for (Resource resource : resources) {
// 加載BeanDefinintion
counter += loadBeanDefinitions(resource);
}
// 返回加載Bean的數(shù)量
return counter;
}
XmlBeanDefinitionReader
// 從配置文件中加載Bean
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource);
}
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
// 將Resource資源轉(zhuǎn)化為輸入流InputStream
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// 執(zhí)行加載Bean的過程
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();
}
}
}
// 加載Bean的函數(shù)
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 加載XML文件,構(gòu)造XML Document對象
Document doc = doLoadDocument(inputSource, resource);
// 注冊Bean
return registerBeanDefinitions(doc, resource);
}
// 拋出各種異常
......
}
Bean的解析與注冊
DefaultBeanDefinitionDocumentReader
// XML配置文件中beans元素
public static final String NESTED_BEANS_ELEMENT = "beans";
// XML配置文件中alias別名元素
public static final String ALIAS_ELEMENT = "alias";
// XML配置文件中name屬性
public static final String NAME_ATTRIBUTE = "name";
// XML配置文件中alias屬性
public static final String ALIAS_ATTRIBUTE = "alias";
// XML配置文件中import元素
public static final String IMPORT_ELEMENT = "import";
// XML配置文件中resource屬性
public static final String RESOURCE_ATTRIBUTE = "resource";
// XML配置文件中profile屬性
public static final String PROFILE_ATTRIBUTE = "profile";
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
// 創(chuàng)建Bean解析代理工具類
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
// 解析profile屬性
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
preProcessXml(root);
// 解析XML并執(zhí)行Bean注冊
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
// root根節(jié)點是默認標簽
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
// 遍歷XML Document的每個節(jié)點
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
// 解析默認標簽
parseDefaultElement(ele, delegate);
}
else {
// 解析自定義標簽
delegate.parseCustomElement(ele);
}
}
}
}
// root根節(jié)點是自定義標簽
else {
delegate.parseCustomElement(root);
}
}
// 解析XML配置文件的節(jié)點元素
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
// 如果是Import元素
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);
}
// 如果是嵌套Bean元素(Beans)
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
Import解析
雖然每個單獨的XML配置文件都代表體系結(jié)構(gòu)中的邏輯層或模塊郭厌,但我們可以從多個XML片段中加載Bean定義袋倔。如項目中有多個Resource位置,可以使用一個或多個<import />從另外的XML文件中加載Bean定義折柠。
標簽用法示例:
<import resource="applicationDao.xml" />
<import resource="applicationService.xml" />
解析標簽的源碼:
DefaultBeanDefinitionDocumentReader
protected void importBeanDefinitionResource(Element ele) {
String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
if (!StringUtils.hasText(location)) {
getReaderContext().error("Resource location must not be empty", ele);
return;
}
// 解析路徑和占位符
location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
// 解析好的資源要放到Set里面
Set<Resource> actualResources = new LinkedHashSet<Resource>(4);
// 解析location是相對路徑還是絕對路徑
boolean absoluteLocation = false;
try {
absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
}
catch (URISyntaxException ex) {
// cannot convert to an URI, considering the location relative
// unless it is the well-known Spring prefix "classpath*:"
}
// 如果是絕對路徑
if (absoluteLocation) {
try {
// 直接根據(jù)路徑加載相應(yīng)的配置文件
int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
if (logger.isDebugEnabled()) {
logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");
}
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error(
"Failed to import bean definitions from URL location [" + location + "]", ele, ex);
}
}
else {
try {
int importCount;
// 如果是相對路徑宾娜,則先根據(jù)路徑得到Resource
Resource relativeResource = getReaderContext().getResource().createRelative(location);
// 如果Resource存在
if (relativeResource.exists()) {
importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
actualResources.add(relativeResource);
}
else {
// Resource類解析不成功,在classpath路徑中去加載扇售。如果沒有則拋出異常
String baseLocation = getReaderContext().getResource().getURL().toString();
importCount = getReaderContext().getReader().loadBeanDefinitions(
StringUtils.applyRelativePath(baseLocation, location), actualResources);
}
if (logger.isDebugEnabled()) {
logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");
}
}
catch (IOException ex) {
getReaderContext().error("Failed to resolve current resource location", ele, ex);
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]",
ele, ex);
}
}
Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]);
getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}
Alias別名注冊
每個bean具有一個或多個標識符前塔。這些標識符在承載Bean的容器內(nèi)必須是唯一的。 Bean通常只有一個標識符缘眶,但是如果需要多個標識符嘱根,則多余的標識符可以被視為別名。
標簽用法示例:
<alias name="dataSource" alias="systemA-dataSource"/>
<alias name="dataSource" alias="systemB-dataSource"/>
在Bean定義中巷懈,可以通過使用id屬性最多指定的一個名稱该抒,同時可以通過name屬性中定義任意數(shù)量的其他名稱來為Bean提供多個名稱。但在定義Bean的地方指定所有別名可能并不能滿足需求顶燕,有時需要在其他地方為Bean定義別名凑保。
解析標簽的源碼:
SimpleAliasRegistry
// 存放別名的緩存
private final Map<String, String> aliasMap = new ConcurrentHashMap<String, String>
// 根據(jù)Bean的別名進行注冊
public void registerAlias(String name, String alias) {
Assert.hasText(name, "'name' must not be empty");
Assert.hasText(alias, "'alias' must not be empty");
synchronized (this.aliasMap) {
// 如果別名和名字相同
if (alias.equals(name)) {
this.aliasMap.remove(alias);
}
else {
// 如果別名和名字不相同,根據(jù)別名獲取Bean名稱
String registeredName = this.aliasMap.get(alias);
if (registeredName != null) {
// 如果緩存中已經(jīng)存在該別名涌攻,不需要注冊到緩存
if (registeredName.equals(name)) {
// An existing alias - no need to re-register
return;
}
// 如果不允許相同的Bean使用不同的名稱則拋出異常
if (!allowAliasOverriding()) {
throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +
name + "': It is already registered for name '" + registeredName + "'.");
}
}
// 對別名進行循環(huán)檢查
checkForAliasCircle(name, alias);
// 把別名放入別名緩存
this.aliasMap.put(alias, name);
}
}
}
// 別名循環(huán)檢查
public boolean hasAlias(String name, String alias) {
for (Map.Entry<String, String> entry : this.aliasMap.entrySet()) {
// 獲取Bean注冊名
String registeredName = entry.getValue();
// 判斷name參數(shù)和Bean注冊名是否相同
if (registeredName.equals(name)) {
// 獲取別名
String registeredAlias = entry.getKey();
// 判斷別名是否相同
// 遞歸調(diào)用hasAlias
if (registeredAlias.equals(alias) || hasAlias(registeredAlias, alias)) {
return true;
}
}
}
return false;
}
別名循環(huán)檢查:A為名稱欧引,B為A的別名,需要注冊別名<B, A>
- 檢查B是否有別名恳谎,如果沒有則返回false
- 如果B有別名C芝此,檢查C是否與A相同。如果相同返回true因痛,說明有別名循環(huán)婚苹。如果不相同遞歸hasAlias(C, B)方法
- 如果C無別名,返回false鸵膏;如果C有別名D且等于A膊升,返回true。如果不相同繼續(xù)遞歸hasAlias(D, B)
Bean注冊
Spring會自動檢測構(gòu)造型類谭企,并向容器注冊相應(yīng)的BeanDefinition廓译。
DefaultBeanDefinitionDocumentReader
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 解析XML中的BeanDefinition元素
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 注冊BeanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// 發(fā)送注冊事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
BeanDefinitionParserDelegate
基于單一職責的緣故评肆,BeanDefinitionParserDelegate專門負責解析XML元素的工作,而DefaultBeanDefinitionDocumentReader則主要負責讀取XML配置文件的職責非区。
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
// 獲取id屬性
String id = ele.getAttribute(ID_ATTRIBUTE);
// 獲取name屬性
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
// 定義別名list
List<String> aliases = new ArrayList<String>();
if (StringUtils.hasLength(nameAttr)) {
// 因為可以多個別名用瓜挽,所以解析成別名數(shù)組
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
// beanName默認為id
String beanName = id;
// 如果沒有beanName,那么取出別名數(shù)組中的第一個作為beanName
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isDebugEnabled()) {
logger.debug("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
// 生成Bean名
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
// 生成Bean名
beanName = this.readerContext.generateBeanName(beanDefinition);
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
// 解析Bean定義不考慮名稱或別名院仿。如果在Bean解析過程中產(chǎn)生異常秸抚,則返回null
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
String className = null;
// 解析Bean的class屬性
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
try {
String parent = null;
// 解析parent屬性
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
// 為指定的類名和Parent名稱創(chuàng)建一個BeanDefinition
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 解析Bean元素的屬性并應(yīng)用于Bean
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
// 設(shè)置Bean的描述信息
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
// 解析Bean定義的元數(shù)據(jù)信息(meta以鍵值對形式存在)
parseMetaElements(ele, bd);
// 解析lookup-method元素
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
// 解析replaced-method元素
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
// 解析構(gòu)造函數(shù)參數(shù)
parseConstructorArgElements(ele, bd);
// 解析property元素
parsePropertyElements(ele, bd);
// 解析qualifier元素
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
}
catch (NoClassDefFoundError err) {
error("Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {
error("Unexpected failure during bean definition parsing", ele, ex);
}
finally {
this.parseState.pop();
}
return null;
}
BeanDefinitionReaderUtils
該類的主要職責用于生產(chǎn)新的BeanDefiniti實例速和,給Bean生成一個名稱及調(diào)用BeanDefinitionRegistry進行Bean的注冊歹垫。
public static String generateBeanName(
BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean)
throws BeanDefinitionStoreException {
String generatedBeanName = definition.getBeanClassName();
if (generatedBeanName == null) {
// 如果有父類,名稱為:definition.getParentName() + “$child”
if (definition.getParentName() != null) {
generatedBeanName = definition.getParentName() + "$child";
}
// 如果有指定的工廠類颠放,名稱為:definition.getFactoryBeanName() + “$created”
else if (definition.getFactoryBeanName() != null) {
generatedBeanName = definition.getFactoryBeanName() + "$created";
}
}
if (!StringUtils.hasText(generatedBeanName)) {
throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither " +
"'class' nor 'parent' nor 'factory-bean' - can't generate bean name");
}
String id = generatedBeanName;
if (isInnerBean) {
// 如果是innerBean排惨,名稱為
id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition);
}
else {
// 如果不是InnerBean則為頂層Bean,使用簡單的類名碰凶。計數(shù)器加1
int counter = -1;
while (counter == -1 || registry.containsBeanDefinition(id)) {
counter++;
id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + counter;
}
}
return id;
}
-
parent
Bean定義可以包含許多配置信息暮芭,包括容器相關(guān)的信息(比如初始化方法,靜態(tài)工廠方法等等)以及構(gòu)造函數(shù)參數(shù)和屬性的值欲低。子Bean可以定義從父Bean定義中繼承配置數(shù)據(jù)辕宏,而后它可以根據(jù)需要覆蓋某些值,或添加其他值砾莱。使用父子Bean可以節(jié)省很多輸入工作瑞筐。 -
lookup-method
lookup-method注入是容器重寫B(tài)ean上的方法的一種能力,它可以在容器中根據(jù)一個Bean的名字返回查找結(jié)果腊瑟。lookup-method通常涉及Prototype Bean聚假。Spring框架通過使用CGLIB來覆蓋該方法的子類以實現(xiàn)lookup-method的注入。該功能可用于在一些可插拔的功能上解除依賴闰非。 -
replace-method
用于在運行時調(diào)用使用新的方法替換原有的方法膘格,還能動態(tài)的改變原有方法的邏輯。
DefaultListableBeanFactory
// 手動注冊的單例名稱列表
private volatile Set<String> manualSingletonNames = new LinkedHashSet<String>(16);
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");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
// 對于AbstractBeanDefinition屬性中的methodOverrides校驗
// 校驗methodOverrides是否與工廠方法并存或者methodOverrides對應(yīng)的方法根本不存在
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
// 從緩存中根據(jù)beanName獲取BeanDefinition
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
// 如果BeanDefinition存在并且不允許同名覆蓋财松,則拋出異常
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + existingDefinition + "] bound.");
}
// Bean的角色檢查
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isWarnEnabled()) {
logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
// 如果名字相同瘪贱,但是BeanDefinition不同打印覆蓋日志
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isInfoEnabled()) {
logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
// 在緩存中注冊Bean
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
// 檢查工廠的Bean創(chuàng)建階段是否已經(jīng)開始
if (hasBeanCreationStarted()) {
// 進入創(chuàng)建階段,此時無法再修改啟動時集合元素(為了穩(wěn)定迭代)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
// beanName在manualSingletonNames中辆毡,說明是手動注冊
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// 工廠還未到創(chuàng)建階段菜秦,仍然在注冊階段
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
// 待注冊的Bean的已經(jīng)在beanDefinitionMap緩存中存在,或者已經(jīng)存在于單例Bean緩存中
if (existingDefinition != null || containsSingleton(beanName)) {
// 重置給定Bean的所有BeanDefinition緩存胚迫,包括從其派生的Bean的緩存
resetBeanDefinition(beanName);
}
}
AbstractBeanFactory
// 保存在至少被創(chuàng)建過一次的beanName
// 如果這個集合中存在beanName喷户,那么說明已經(jīng)進入了Bean創(chuàng)建階段
private final Set<String> alreadyCreated =
Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(256))