SpringIOC源碼解析(上)

注意,看完這篇文章須要很長很長很長時間。。。php

準備工做

本文會分析Spring的IOC模塊的總體流程,分析過程須要使用一個簡單的demo工程來啓動Spring,demo工程我以備好,須要的童鞋自行在下方連接下載:node

1
https://github.com/shiyujun/spring-framework
Demo工程示例代碼

本文源碼分析基於Spring5.0.0,因此pom文件中引入5.0的依賴git

1
2
3
4
5
6
7
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.0.RELEASE</version>
</dependency>
</dependencies>

而後寫一個簡單的接口和實現類github

1
2
3
4
5
6
7
8
9
public interface IOCService {
public String hollo();
}

public class IOCServiceImpl implements IOCService {
public String hollo() {
return "Hello,IOC";
}
}

新建一個application-ioc.xmlweb

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" default-autowire="byName">

<bean id="iocservice" class="cn.shiyujun.service.impl.IOCServiceImpl"/>
</beans>

啓動Springspring

1
2
3
4
5
6
7
public class IOCDemo {
public static void main (String args[]){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application-ioc.xml");
IOCService iocService=context.getBean(IOCService.class);
System.out.println(iocService.hollo());
}
}

上方一個簡單的demo工程相信各位童鞋在剛剛學習Spring的時候就已經玩的特別6了。我就不詳細的說明了,直接開始看源碼吧數據庫

ClassPathXmlApplicationContext

背景調查

在文章開始的demo工程中,我選擇使用了一個xml文件來配置了接口和實現類之間的關係,而後使用了ClassPathXmlApplicationContext這個類來加載這個配置文件。如今咱們就先來看一下這個類究竟是個什麼東東
首先看一下繼承關係圖(只保留了跟本文相關的,省略了不少其餘的繼承關係)
1編程

能夠看到左下角的就是咱們今天的主角ClassPathXmlApplicationContext、而後它的旁邊是一個同門師兄弟FileSystemXmlApplicationContext。看名字就能夠知道它們哥倆都是經過加載配置文件來啓動Spring的,只不過一個是從程序內加載一個是從系統內加載。設計模式

除了這兩個還有一個類AnnotationConfigApplicationContext比較值得咱們關注,這個類是用來處理註解式編程的。數組

而最上邊的ApplicationContext則是大名鼎鼎的Spring核心上下文了

源碼分析

看一下這個類的源代碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
//配置文件數組
private Resource[] configResources;

// 指定ApplicationContext的父容器
public ClassPathXmlApplicationContext(ApplicationContext parent) {
super(parent);
}

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {

super(parent);
// 根據提供的路徑,處理成配置文件數組(以分號、逗號、空格、tab、換行符分割)
setConfigLocations(configLocations);

if (refresh) {
refresh();
}
}
}

能夠看到總體來看源碼比較簡單,只有setConfigLocationsrefresh兩個方法沒有看到具體的實現。可是若是你由於這個而小巧了Spring那可就大錯特錯了,setConfigLocations只是一個開胃小菜,refresh纔是咱們本文的重點

setConfigLocations

setConfigLocations方法的主要工做有兩個:建立環境對象ConfigurableEnvironment和處理ClassPathXmlApplicationContext傳入的字符串中的佔位符

跟着setConfigLocations方法一直往下走

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void setConfigLocations(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++) {
//往下看
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}


protected String resolvePath(String path) {
return getEnironment().resolveRequiredPlaceholders(path);
}

這裏getEnironment()就涉及到了建立環境變量相關的操做了

獲取環境變量
1
2
3
4
5
6
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
this.environment = createEnvironment();
}
return this.environment;
}

看一下ConfigurableEnvironment這個接口的繼承圖(1張沒能截全,兩張一塊看)
1
1
這個接口比較重要的就是兩部份內容了,一個是設置Spring的環境就是咱們常常用的spring.profile配置。另外就是系統資源Property

接着看createEnvironment()方法,發現它返回了一個StandardEnvironment類,而這個類中的customizePropertySources方法就會往資源列表中添加Java進程中的變量和系統的環境變量

1
2
3
4
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}
處理佔位符

再次回到 resolvePath方法後跟進經過上方獲取的ConfigurableEnvironment接口的resolveRequiredPlaceholders方法,終點就是下方的這個方法。這個方法主要就是處理全部使用${}方式的佔位符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
protected String parseStringValue(
String value, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) {

StringBuilder result = new StringBuilder(value);
int startIndex = value.indexOf(this.placeholderPrefix);
while (startIndex != -1) {
int endIndex = findPlaceholderEndIndex(result, startIndex);
if (endIndex != -1) {
String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
String originalPlaceholder = placeholder;
if (!visitedPlaceholders.add(originalPlaceholder)) {
throw new IllegalArgumentException(
"Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
}
placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
// Now obtain the value for the fully resolved key...
String propVal = placeholderResolver.resolvePlaceholder(placeholder);
if (propVal == null && this.valueSeparator != null) {
int separatorIndex = placeholder.indexOf(this.valueSeparator);
if (separatorIndex != -1) {
String actualPlaceholder = placeholder.substring(0, separatorIndex);
String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
if (propVal == null) {
propVal = defaultValue;
}
}
}
if (propVal != null) {
// Recursive invocation, parsing placeholders contained in the
// previously resolved placeholder value.
propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
if (logger.isTraceEnabled()) {
logger.trace("Resolved placeholder '" + placeholder + "'");
}
startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());
}
else if (this.ignoreUnresolvablePlaceholders) {
// Proceed with unprocessed value.
startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
}
else {
throw new IllegalArgumentException("Could not resolve placeholder '" +
placeholder + "'" + " in value \"" + value + "\"");
}
visitedPlaceholders.remove(originalPlaceholder);
}
else {
startIndex = -1;
}
}

return result.toString();
}

refresh

配置文件名稱解析完畢後,就到了最關鍵的一步refresh方法。這個方法,接下來會用超級長的篇幅來解析這個方法

先看一下這個方法裏大體內容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();

// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.
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();
}
}
}

是否是看着有點懵,不要着急,一行一行往下看,不研究明白誓不罷休

1. synchronized

爲了不refresh() 還沒結束,再次發起啓動或者銷燬容器引發的衝突

2. prepareRefresh()

作一些準備工做,記錄容器的啓動時間、標記「已啓動」狀態、檢查環境變量等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);

if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}

// 初始化加載配置文件方法,並無具體實現,一個留給用戶的擴展點
initPropertySources();

// 檢查環境變量
getEnvironment().validateRequiredProperties();

this.earlyApplicationEvents = new LinkedHashSet<>();
}

其中檢查環境變量的核心方法爲,簡單來講就是若是存在環境變量的value爲空的時候就拋異常,而後中止啓動Spring

1
2
3
4
5
6
7
8
9
10
11
public void validateRequiredProperties() {
MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
for (String key : this.requiredProperties) {
if (this.getProperty(key) == null) {
ex.addMissingRequiredProperty(key);
}
}
if (!ex.getMissingRequiredProperties().isEmpty()) {
throw ex;
}
}

基於這個特性咱們能夠作一些擴展,提早在集合requiredProperties中放入咱們這個項目必須存在的一些環境變量。假說咱們的生產環境數據庫地址、用戶名和密碼都是使用環境變量的方式注入進去來代替測試環境的配置,那麼就能夠在這裏添加這個校驗,在程序剛啓動的時候就能發現問題

3. obtainFreshBeanFactory()

乍一看這個方法也沒幾行代碼,可是這個方法負責了BeanFactory的初始化、Bean的加載和註冊等事件

1
2
3
4
5
6
7
8
9
10
11
12

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 核心
refreshBeanFactory();

// 返回剛剛建立的 BeanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
BeanFactory

先看refreshBeanFactory()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

protected final void refreshBeanFactory() throws BeansException {
// 判斷當前ApplicationContext是否存在BeanFactory,若是存在的話就銷燬全部 Bean,關閉 BeanFactory
// 注意,一個應用能夠存在多個BeanFactory,這裏判斷的是當前ApplicationContext是否存在BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 初始化DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());

// 設置 BeanFactory 的兩個配置屬性:是否容許 Bean 覆蓋、是否容許循環引用
customizeBeanFactory(beanFactory);

// 加載 Bean 到 BeanFactory 中
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

這裏一開始就實例化了一個DefaultListableBeanFactory,先看一下這個類的繼承關係
2
能夠看到這個哥們的背景至關大,全部關於容器的接口、抽象類他都繼承了。再看他的方法

2
2
2
2
這方法簡直多的嚇人,妥妥的Spring家族超級富二代。看他的方法名稱相信就能夠猜出他大部分的功能了

BeanDefinition

在看loadBeanDefinitions()這個方法以前,就必須瞭解一個東西了。那就是:BeanDefinition

咱們知道BeanFactory是一個Bean容器,而BeanDefinition就是Bean的一種形式(它裏面包含了Bean指向的類、是否單例、是否懶加載、Bean的依賴關係等相關的屬性)。BeanFactory中就是保存的BeanDefinition。

看BeanDefinition的接口定義

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

// Bean的生命週期,默認只提供sington和prototype兩種,在WebApplicationContext中還會有request, session, globalSession, application, websocket 等
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;


// 設置父Bean
void setParentName(String parentName);

// 獲取父Bean
String getParentName();

// 設置Bean的類名稱
void setBeanClassName(String beanClassName);

// 獲取Bean的類名稱
String getBeanClassName();


// 設置bean的scope
void setScope(String scope);

String getScope();

// 設置是否懶加載
void setLazyInit(boolean lazyInit);

boolean isLazyInit();

// 設置該Bean依賴的全部Bean
void setDependsOn(String... dependsOn);

// 返回該Bean的全部依賴
String[] getDependsOn();

// 設置該Bean是否能夠注入到其餘Bean中
void setAutowireCandidate(boolean autowireCandidate);

// 該Bean是否能夠注入到其餘Bean中
boolean isAutowireCandidate();

// 同一接口的多個實現,若是不指定名字的話,Spring會優先選擇設置primary爲true的bean
void setPrimary(boolean primary);

// 是不是primary的
boolean isPrimary();

// 指定工廠名稱
void setFactoryBeanName(String factoryBeanName);
// 獲取工廠名稱
String getFactoryBeanName();
// 指定工廠類中的工廠方法名稱
void setFactoryMethodName(String factoryMethodName);
// 獲取工廠類中的工廠方法名稱
String getFactoryMethodName();

// 構造器參數
ConstructorArgumentValues getConstructorArgumentValues();

// Bean 中的屬性值,後面給 bean 注入屬性值的時候會說到
MutablePropertyValues getPropertyValues();

// 是否 singleton
boolean isSingleton();

// 是否 prototype
boolean isPrototype();

// 若是這個 Bean 是被設置爲 abstract,那麼不能實例化,經常使用於做爲 父bean 用於繼承
boolean isAbstract();

int getRole();
String getDescription();
String getResourceDescription();
BeanDefinition getOriginatingBeanDefinition();
}
讀取配置文件

如今能夠看loadBeanDefinitions()方法了,這個方法會根據配置,加載各個 Bean,而後放到 BeanFactory 中

1
2
3
4
5
6
7
8
9
10
11
12
@Overrideprotected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 實例化XmlBeanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

// 初始化 BeanDefinitionReader
initBeanDefinitionReader(beanDefinitionReader);
// 接着往下看
loadBeanDefinitions(beanDefinitionReader);
}
1
2
3
4
5
6
7
8
9
10
11

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}

第一個if是看有沒有系統指定的配置文件,若是沒有的話就走第二個if加載咱們最開始傳入的classpath:application-ioc.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int counter = 0;
// 循環,處理全部配置文件,我們這裏就傳了一個
for (Resource resource : resources) {
// 繼續往下看
counter += loadBeanDefinitions(resource);
}
// 最後返回加載的全部BeanDefinition的數量
return counter;
}

@Override
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}


public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}

if (resourceLoader instanceof ResourcePatternResolver) {
try {
//將配置文件轉換爲Resource對象
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
//接着往下看
int loadCount = loadBeanDefinitions(resources);
if (actualResources != null) {
for (Resource resource : resources) {
actualResources.add(resource);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
}
return loadCount;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// Can only load single resources by absolute URL.
Resource resource = resourceLoader.getResource(location);
int loadCount = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
}
}

離解析愈來愈近了
這裏先小小的看一下Spring中的設計模式,咱們跟着loadBeanDefinitions()方法往下走,最終會進入類XmlBeanDefinitionReader,這是由於咱們這裏要解析的配置文件是XML。若是咱們使用Java類配置或者是Groovy的話就是另外的類了。看一下這個類繼承圖:
2

接着看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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.getResource());
}

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 {
//獲取文件流
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//加載
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();
}
}
}

下面是分爲兩步

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//將 xml 文件轉換爲 Document 對象
Document doc = doLoadDocument(inputSource, resource);
//根據Document對象註冊Bean
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}

文件轉換就不詳細展開了,接着往下看

註冊Bean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//構建讀取Document的工具類
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//獲取已註冊的bean數量
int countBefore = getRegistry().getBeanDefinitionCount();
// 在這接着往下看
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//總註冊的bean減去以前註冊的bean就是本次註冊的bean
return getRegistry().getBeanDefinitionCount() - countBefore;
}
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
//獲取Document的根節點
Element root = doc.getDocumentElement();
//繼續往下
doRegisterBeanDefinitions(root);
}

protected void doRegisterBeanDefinitions(Element root) {
// 當前根節點
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);

if (this.delegate.isDefaultNamespace(root)) {
// 獲取 <beans ... profile="***" /> 中的 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);
// 往下看
parseBeanDefinitions(root, this.delegate);
// 後置擴展點
postProcessXml(root);

this.delegate = parent;
}
改變bean定義的擴展點

preProcessXml和postProcessXml着兩個辦法是留給咱們實現DefaultBeanDefinitionDocumentReader方法後自定義實現的

解析XML

接下來,看核心解析方法 parseBeanDefinitions()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
// default namespace 涉及到的就四個標籤 <import />、<alias />、<bean /> 和 <beans />
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
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)) {
// 解析 default namespace 下面的幾個元素
parseDefaultElement(ele, delegate);
}
else {
// 解析其餘 namespace 的元素
delegate.parseCustomElement(ele);
}
}
}
}
else {
// 解析其餘 namespace 的元素
delegate.parseCustomElement(root);
}
}

接着往下看這些標籤的處理方式

default標籤處理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
// 處理 <import /> 標籤
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
// 處理 <alias /> 標籤
// <alias name="fromName" alias="toName"/>
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
// 處理 <bean /> 標籤訂義
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// 處理 <beans /> 標籤
doRegisterBeanDefinitions(ele);
}
}

簡單看一下 標籤的處理方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//建立BeanDefinition
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
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));
}
}

先從第一行往下看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

List<String> aliases = new ArrayList<String>();

// 將 name 屬性的定義按照 「逗號、分號、空格」 切分,造成一個 別名列表數組,
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}

String beanName = id;
// 若是沒有指定id, 那麼用別名列表的第一個名字做爲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);
}

// 根據 <bean ...>...</bean> 中的配置建立 BeanDefinition,而後把配置中的信息都設置到實例中,
// 這行執行完畢,一個 BeanDefinition 實例就出來了。等下接着往下看
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);

// <bean /> 標籤完成
if (beanDefinition != null) {
// 若是沒有設置 id 和 name,那麼此時的 beanName 就會爲 null
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);

String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
// 把 beanClassName 設置爲 Bean 的別名
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);
// 返回 BeanDefinitionHolder
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}

return null;
}
建立BeanDefinition

接着是最重要的地方,如何根據配置建立 BeanDefinition 實例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) {

this.parseState.push(new BeanEntry(beanName));

String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}

try {
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
// 建立 BeanDefinition,而後設置類信息
AbstractBeanDefinition bd = createBeanDefinition(className, parent);

// 設置 BeanDefinition 的一堆屬性,這些屬性定義在 AbstractBeanDefinition 中
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

/**
* 下面的一堆是解析 <bean>......</bean> 內部的子元素,
* 解析出來之後的信息都放到 bd 的屬性中
*/

// 解析 <meta />
parseMetaElements(ele, bd);
// 解析 <lookup-method />
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
// 解析 <replaced-method />
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
// 解析 <constructor-arg />
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;
}

終於終於這麼長時間把這個BeanDefinition搞出來了,太不容易了!!!

接着回到剛纔的代碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 上面說的一堆
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 若是有自定義屬性的話,進行相應的解析
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 註冊Bean
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// 註冊完成後,發送事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
Bean的註冊

此次看註冊bean的實現

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {

String beanName = definitionHolder.getBeanName();
// 註冊這個 Bean
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

// 若是配置有別名的話,也要根據別名所有註冊一遍
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}

又是一個長方法。。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
@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");

if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(...);
}
}

BeanDefinition oldBeanDefinition;

// 全部的 Bean 註冊後都會被放入到這個beanDefinitionMap 中,查看是否已存在這個bean
oldBeanDefinition = this.beanDefinitionMap.get(beanName);

// 處理重複名稱的 Bean 定義的狀況
if (oldBeanDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
// 若是不容許覆蓋的話,拋異常
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// 用框架定義的 Bean 覆蓋用戶自定義的 Bean
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(oldBeanDefinition)) {
// 用新的 Bean 覆蓋舊的 Bean
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
else {
// log...用同等的 Bean 覆蓋舊的 Bean
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
// 覆蓋
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
// 判斷是否已經有其餘的 Bean 開始初始化了.注意,"註冊Bean" 這個動做結束,Bean 依然尚未初始化 在 Spring 容器啓動的最後,會 預初始化 全部的 singleton beans
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<String>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {


// 將 BeanDefinition 放到這個 map 中,這個 map 保存了全部的 BeanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
// 這是個 ArrayList,因此會按照 bean 配置的順序保存每個註冊的 Bean 的名字
this.beanDefinitionNames.add(beanName);
// 這是個 LinkedHashSet,表明的是手動註冊的 singleton bean,
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}

if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}

到這裏已經初始化了 Bean 容器,的配置也相應的轉換爲了一個個BeanDefinition,而後註冊了全部的BeanDefinition到beanDefinitionMap

4. prepareBeanFactory()

如今回到最開始的refresh()方法
prepareBeanFactory()這個方法主要會設置BeanFactory的類加載器、添加幾個 BeanPostProcessor、手動註冊幾個特殊的bean

繼續擼代碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {

// 設置爲加載當前ApplicationContext類的類加載器
beanFactory.setBeanClassLoader(getClassLoader());

// 設置 BeanExpressionResolver
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));

beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

// 這裏是Spring的又一個擴展點
//在全部實現了Aware接口的bean在初始化的時候,這個 processor負責回調,
// 這個咱們很經常使用,如咱們會爲了獲取 ApplicationContext 而 implement ApplicationContextAware
// 注意:它不只僅回調 ApplicationContextAware,還會負責回調 EnvironmentAware、ResourceLoaderAware 等
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

// 下面幾行的意思就是,若是某個 bean 依賴於如下幾個接口的實現類,在自動裝配的時候忽略它們,Spring 會經過其餘方式來處理這些依賴。
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

//下面幾行就是爲特殊的幾個 bean 賦值,若是有 bean 依賴瞭如下幾個,會注入這邊相應的值
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);

// 註冊 事件監聽器
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

// 若是存在bean名稱爲loadTimeWeaver的bean則註冊一個BeanPostProcessor
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}

// 若是沒有定義 "environment" 這個 bean,那麼 Spring 會 "手動" 註冊一個
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
// 若是沒有定義 "systemProperties" 這個 bean,那麼 Spring 會 "手動" 註冊一個
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
// 若是沒有定義 "systemEnvironment" 這個 bean,那麼 Spring 會 "手動" 註冊一個
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
5. postProcessBeanFactory()

這個比較簡單,又是Spring的一個擴展點

若是有Bean實現了BeanFactoryPostProcessor接口,
那麼在容器初始化之後,Spring 會負責調用裏面的 postProcessBeanFactory 方法。具體的子類能夠在這步的時候添加一些特殊的 BeanFactoryPostProcessor 的實現類或作點什麼事

6. invokeBeanFactoryPostProcessors()

調用 BeanFactoryPostProcessor 各個實現類的 postProcessBeanFactory(factory) 方法

7. registerBeanPostProcessors()

又是一個擴展點

註冊 BeanPostProcessor 的實現類,注意不是BeanFactoryPostProcessor
此接口有兩個方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
分別會在Bean初始化以前和初始化以後獲得執行

8. initMessageSource()

初始化當前 ApplicationContext 的 MessageSource,有想了解國際化的相關知識能夠深刻研究一下

9. initApplicationEventMulticaster()

這個方法主要爲初始化當前 ApplicationContext 的事件廣播器

擼代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private void initApplicationEventMulticaster() throws BeansException {
//若是用戶配置了自定義事件廣播器,就使用用戶的
if (containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME )) {
this.applicationEventMulticaster = (ApplicationEventMulticaster)
getBean( APPLICATION_EVENT_MULTICASTER_BEAN_NAME ,
ApplicationEventMulticaster.class );
if (logger.isInfoEnabled()) {
logger.info("Using ApplicationEventMulticaster ["
+ this. applicationEventMulticaster + "]" );
}
}else {
//使用默認的時間廣播器
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster();
if (logger.isInfoEnabled()) {
logger.info("Unable to locate ApplicationEventMulticaster with name '"+
APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
"': using default [" + this .applicationEventMulticaster + "]");
}
}
}
10. onRefresh()

又是一個擴展點,子類能夠在這裏來搞事情

11. registerListeners()

註冊事件監聽器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
protected void registerListeners() {
//先添加手動set的一些監聽器
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}

//取到監聽器的名稱,設置到廣播器
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}

// 若是存在早期應用事件,發佈
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}

看到這裏不要覺得文章結束了,上方那麼大的篇幅其實總結起來僅僅只介紹了Bean容器的建立過程,因爲平臺的字數限制因此本篇文章只能寫到這裏了。後續內容請看明天的下篇

相關文章
相關標籤/搜索