前提

為什麼寫本文?

  1. 深入源碼學習SpringBoot的IoC容器原理
  2. 網上大部分資料都是基於xml的舊版本Spring講解,筆者入門Spring已經從SpringBoot開始,甚至至今未用過xml的方式,故有了寫一遍SpringBoot的IoC容器原理的文章。

本文特點

  1. 代碼基於SpringBoot的2.1.1.RELEASE版本。
  2. 以代碼執行的順序講解,符合人的一般理解思路,但不會深入到每一行代碼,重點關注關鍵點,避免迷失在龐大的框架代碼和複雜的邏輯裡面。

概述

控制反轉(Inversion of Control,縮寫為IoC),是面向對象編程中的一種設計原則,可以用來減低計算機代碼之間的耦合度。其中最常見的方式叫做依賴注入(Dependency Injection,簡稱DI)。通過控制反轉,對象在被創建的時候,由一個調控系統內所有對象的外界實體,將其所依賴的對象的引用傳遞給它。也可以說,依賴被注入到對象中。

即IoC是一種設計原則,DI是IoC的一種實現。IoC是Spring容器的內核,AOP、聲明式事務都是基於IoC的基礎實現。


準備

1,類裝載器 ClassLoader

ClassLoader就是解析類的節碼文件(.class文件)並構造出JVM能夠識別的Class類對象。

2,java反射機制

從Class對象動態創建對應的Object對象,SpringBoot利用反射實例化Bean並建立Bean之間的依賴關係。

3,資源訪問

通過Resource和ResourceLoader載入.xml、.properties、.factories文件。

4,BeanFactory

Bean工廠BeanFactory是Spring框架最核心的介面,它提供了IoC的配置機制。

5,ApplicationContext

應用上下文ApplicationContext建立在BeanFactory基礎之上,提供了更多面嚮應用的功能。SpringBoot使用的是ApplicationContext的子類AnnotationConfigServletWebServerApplicationContext。

對於BeanFactory和ApplicationContext的比較,BeanFactory是Spring框架的基礎設施,面向Spring本身,ApplicationContext面向使用Spring框架的開發者,如果將Spring容器比作一輛汽車,那麼BeanFactory就是汽車的發動機,而ApplicationContext則是一輛完整的汽車,它不但包括發動機,還包括離合器、變速器及底盤等其他組件。

6,BeanDefinition

BeanDefinition是Bean在IoC容器的內部表示。

7,BeanDefinitionRegistry

BeanDefinitionRegistry是IoC容器的bean註冊表,用於保存各種Bean。

8,BeanPostProcessor

bean後置處理器,有postProcessBeforeInitialization和postProcessAfterInitialization兩個方法,允許在bean的初始化前後對bean進行處理,注意,這裡是初始化。


GO!

所以,我們要引入SpringBoot的基礎依賴

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

程序入口

@SpringBootApplication
public class DemoApplication {

public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}

}

org.springframework.boot.SpringApplication#SpringApplication(org.springframework.core.io.ResourceLoader, java.lang.Class<?>...)

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//通過Resource和ResourceLoader載入META-INFspring.factories文件
//並通過反射,創建對應的實例
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}

org.springframework.boot.SpringApplication#run(java.lang.String...)

public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
//創建並初始化ApplicationContext和BeanFactory
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//創建IoC容器
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
...
}

org.springframework.context.support.AbstractApplicationContext#refresh

public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();

//舊版本的Spring在這裡初始化BeanFactory,讀取xml配置,並解析成一個個Bean,
// 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);

//調用工廠後處理器
//掃描Bean文件,並解析成一個個Bean
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);

//註冊Bean後處理器
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);

//初始化消息源
// Initialize message source for this context.
initMessageSource();

//初始化應用上下文時間廣播器
// Initialize event multicaster for this context.
initApplicationEventMulticaster();

//初始化其他特殊的Bean,由具體子類實現
// Initialize other special beans in specific context subclasses.
onRefresh();

//註冊事件監聽器
// Check for listener beans and register them.
registerListeners();

//初始化所有單例的Bean,使用懶載入模式的Bean除外
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

//完成刷新並發布容器刷新事件
// Last step: publish corresponding event.
finishRefresh();
}
...
}
}

在org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization創建Bean實例並構建Bean的依賴關係網

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
...

// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
}

最後一步,org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons

public void preInstantiateSingletons() throws BeansException {
...

// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
getBean(beanName);
}
}
}

...
}

該方法首先循環所有的BeanNames,並且調用getBean方法,該方法實際上就是創建bean並遞歸構建依賴關係。

getBean會調用org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

...

//從緩存讀取Bean
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
...

//遞歸獲取依賴
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between " + beanName + " and " + dep + "");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"" + beanName + " depends on missing bean " + dep + "", ex);
}
}
}

//創建bean實例
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

...
return (T) bean;
}

該方法首先會獲取依賴關係,拿著依賴的BeanName 遞歸調用 getBean方法,直到調用 getSingleton 方法返回依賴bean。

getSingleton 方法的參數是org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])返回的實例

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
...

try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean " + beanName + "");
}
return beanInstance;
}
...
}

該方法內部調用org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean方法

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {

// Instantiate the bean.
BeanWrapper instanceWrapper = null;
...
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
...

// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
...

return exposedObject;
}

其中org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance通過反射創建實例,

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean通過遞歸填充Bean。

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)初始化bean。

最後,整個Bean生命週期的活動圖。

Bean的作用域

Spring中Bean的作用域

關於Spring的循環依賴問題

SpringBoot構造器注入循環依賴及解決 - Revivedsun的專欄 - CSDN博客

demo

BinGithub2015/zhihu


參考

精通Spring 4.x 企業應用開發實戰

深入理解 Spring 之源碼剖析IOC

Spring IOC 容器源碼分析
推薦閱讀:
相關文章