最簡 Spring IOC 容器原始碼分析
阿新 • • 發佈:2020-12-11
![](https://img2020.cnblogs.com/other/633265/202012/633265-20201210214458574-271718932.png)
- [前言](#前言)
- [BeanDefinition](#beandefinition)
- [BeanFactory 簡介](#beanfactory-簡介)
- [Web 容器啟動過程](#web-容器啟動過程)
- [bean 的載入](#bean-的載入)
- [FactoryBean](#factorybean)
- [迴圈依賴](#迴圈依賴)
- [bean 生命週期](#bean-生命週期)
- [公眾號](#公眾號)
# 前言
許多文章都是分析的 xml 配置,但是現在 Spring Boot 開發多基於註解。本文從`註解`的角度分析 Spring IOC 容器原始碼。
版本:
- Spring Boot:2.1.6.RELEASE
- Spring FrameWork:5.1.8.RELEASE
- Java 8
文章部分內容參考自:https://www.javadoop.com/post/spring-ioc
# BeanDefinition
BeanDefinition 介面定義了一個包含屬性、構造器引數、其他具體資訊的 bean 例項。
```java
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
// ConfigurableBeanFactory 中只有 2 種:singleton 和 prototype。
// request, session 等是基於 Web 的擴充套件
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
// 不重要
int ROLE_APPLICATION = 0;
int ROLE_SUPPORT = 1;
int ROLE_INFRASTRUCTURE = 2;
// 設定父 Bean 的資訊(繼承父 Bean 的配置資訊)
void setParentName(@Nullable String parentName);
@Nullable
String getParentName();
// 設定 Bean 的類名稱,要通過反射來生成例項
void setBeanClassName(@Nullable String beanClassName);
// 返回當前 Bean 的 class name
String getBeanClassName();
void setScope(@Nullable String scope);
@Nullable
String getScope();
// 是否延遲初始化
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
// 設定該 Bean 依賴的所有的 Bean,並非 @Autowire 標記的
void setDependsOn(@Nullable String... dependsOn);
@Nullable
String[] getDependsOn();
// 設定該 Bean 是否可以注入到其他 Bean 中,只對根據型別注入有效,
// 如果根據名稱注入,即使這邊設定了 false,也是可以的
void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();
// 同一介面的多個實現,如果不指定名字,Spring 會優先選擇設定 primary 為 true 的 bean
void setPrimary(boolean primary);
boolean isPrimary();
// 如果該 Bean 採用工廠方法生成,指定工廠名稱;否則用反射生成
void setFactoryBeanName(@Nullable String factoryBeanName);
@Nullable
String getFactoryBeanName();
// 指定工廠類中的 工廠方法名稱
void setFactoryMethodName(@Nullable String factoryMethodName);
@Nullable
String getFactoryMethodName();
// 返回該 bean 的構造器引數
ConstructorArgumentValues getConstructorArgumentValues();
default boolean hasConstructorArgumentValues() {
return !getConstructorArgumentValues().isEmpty();
}
// Bean 中的屬性值,返回的例項在 bean factory post-processing 期間會被更改
MutablePropertyValues getPropertyValues();
default boolean hasPropertyValues() {
return !getPropertyValues().isEmpty();
}
void setInitMethodName(@Nullable String initMethodName);
@Nullable
String getInitMethodName();
void setDestroyMethodName(@Nullable String destroyMethodName);
@Nullable
String getDestroyMethodName();
void setRole(int role);
int getRole();
void setDescription(@Nullable String description);
@Nullable
String getDescription();
// Read-only attributes
boolean isSingleton();
boolean isPrototype();
boolean isAbstract();
@Nullable
String getResourceDescription();
@Nullable
BeanDefinition getOriginatingBeanDefinition();
}
```
AnnotationConfigUtils#processCommonDefinitionAnnotations(...)
```java
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
else if (abd.getMetadata() != metadata) {
lazy = attributesFor(abd.getMetadata(), Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
}
if (metadata.isAnnotated(Primary.class.getName())) {
abd.setPrimary(true);
}
AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
if (dependsOn != null) {
abd.setDependsOn(dependsOn.getStringArray("value"));
}
AnnotationAttributes role = attributesFor(metadata, Role.class);
if (role != null) {
abd.setRole(role.getNumber("value").intValue());
}
AnnotationAttributes description = attributesFor(metadata, Description.class);
if (description != null) {
abd.setDescription(description.getString("value"));
}
}
```
可以看到,processCommonDefinitionAnnotations 方法會根據註解來填充 AnnotatedBeanDefinition,這些註解有:
- Lazy
- Primary
- DependsOn
- Role
- Description
向上檢視呼叫,發現會在 ConfigurationClassBeanDefinitionReader#registerBeanDefinitionForImportedConfigurationClass 將其註冊為一個 bean definition。
```java
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
AnnotationMetadata metadata = configClass.getMetadata();
AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
configBeanDef.setScope(scopeMetadata.getScopeName());
String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
// 1. 通過註解填充 configBeanDef
AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// 2. 將 bean definition 註冊到 registry 中
this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
configClass.setBeanName(configBeanName);
if (logger.isTraceEnabled()) {
logger.trace("Registered bean definition for imported class '" + configBeanName + "'");
}
}
```
最終會被 AbstractApplicationContext#refresh 的 invokeBeanFactoryPostProcessors(beanFactory) 方法呼叫。
```java
@Override
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();
}
...
}
}
```
# BeanFactory 簡介
BeanFactory 是生產 bean 的工廠,它負責生產和管理各個 bean 例項。從下圖可以看到,ApplicationContext 也是一個 BeanFactory。如果說 BeanFactory 是 Spring 的心臟,那麼 ApplicationContext 就是完整的身軀。
![](https://img2020.cnblogs.com/other/633265/202012/633265-20201210214458881-2064030292.jpg)
ApplicationContext 是應用程式執行時提供配置資訊的通用介面。ApplicationContext 在程式執行時是不可更改的,但是實現類可以重新再入配置資訊。
ApplicationContext 的實現類有很多,比如 AnnotationConfigApplicationContext, AnnotationConfigWebApplicationContext, ClassPathXmlApplicationContext, FileSystemXmlApplicationContext, XmlWebApplicationContext 等。我們上面分析的就是 AnnotationConfigApplicationContext,其採用註解的方式提供配置資訊,這樣我們就不用寫 XML 配置檔案了,非常簡潔。
![](https://img2020.cnblogs.com/other/633265/202012/633265-20201210214459303-1334789932.jpg)
# Web 容器啟動過程
本文使用 Spring Boot 開發,其啟動的程式碼是:
```java
@SpringBootApplication
@EnableScheduling
@EnableAspectJAutoProxy
public class AppApplication {
public static void main(String[] args) {
SpringApplication.run(AppApplication.class, args);
}
}
```
核心的點是這一句:
```java
SpringApplication.run(AppApplication.class, args);
```
SpringApplication 的程式碼就不分析了,明確本次看原始碼的目的是分析`容器原始碼`,Spring Boot 的啟動過程和其他資訊都忽略了,因為 Spring 程式碼實在是龐雜。分析上面的 run 方法,最終會追蹤到 SpringApplication#run(...) 方法。
```java
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Co