Spring IOC 容器預啟動流程原始碼探析
在應用程式中,一般是通過建立ClassPathXmlApplicationContext
或AnnotationConfigApplicationContext
這兩個最底層子類來啟動Spring IOC容器:
ClassPathXmlApplicationContext
:xml
檔案配置版AnnotationConfigApplicationContext
: 註解版
由於當下越來越流行基於Java註解的配置來建立我們的Bean
,所以本文主要以註解版進行探析。
AnnotationConfigApplicationContext
的類關係結構
我們先來看看我們探討的起點
public class Main {
public static void main(String[] args) {
new AnnotationConfigApplicationContext(Config.class);
}
@Configuration
public static class Config{
}
}
demo簡簡單單,那麼,這裡發生了什麼?或許,我們可以先看看AnnotationConfigApplicationContext
的類關係結構:
我們可以看到AnnotationConfigApplicationContext
最上面有兩個頂級介面:
BeanFactory
: Spring的核心介面,純粹的bean容器,主要定義了與Bean
的相關方法ResourceLoader
:資源載入器,定義了getResource
方法
繼承自三個父類:
-
DefaultResourceLoader
: 預設的資源載入器,實現了三種載入資源的方式-
通過
path
載入資源 -
通過
classpath
載入資源 -
通過
URL
載入資源
-
-
AbstractApplicationContext
: 實現了ApplicationContext
介面的抽象類,主要功能-
實現了啟動IOC容器的核心方法:
refresh()
-
釋出事件
-
大量
getBean
相關的操作, 主要通過抽象方法getBeanFactory
基於子類實現 -
大量留於子類擴充套件的空方法
-
訊息國際化
-
-
GenericApplicationContext
:-
使用組合的方式引進了最底層的
BeanFactory
實現類:DefaultListableBeanFactory
-
定義了
registerBean
的相關操作,其實是通過DefaultListableBeanFactory
實現的
-
不難發現,
ApplicationContext
名副其實,確實就是一個應用上下文,對於bean
的相關操作,容器的管理,依舊是由我們的BeanFactory
進行實現。
準備啟動
1. 建立我們的例項:AnnotationConfigApplicationContext
new AnnotationConfigApplicationContext(Config.class);
2.進入到AnnotationConfigApplicationContext
構造方法
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}
3. 呼叫我們的空構造方法,這裡要先例項化我們的父類
3.1 例項化DefaultResourceLoader
public DefaultResourceLoader() {
this.classLoader = ClassUtils.getDefaultClassLoader();
}
ClassUtils.getDefaultClassLoader()
主要有兩步操作
//獲取執行緒上下文的類載入器
ClassLoader cl = = Thread.currentThread().getContextClassLoader();
if(cl == null) //為空則獲取系統的類載入器 即為應用類載入器
cl = ClassLoader.getSystemClassLoader();
這裡我們非Tomcat環境,所以返回的是AppClassLoader
3.2 例項化AbstractApplicationContext
//為BeanFactoryPostProcessor賦初始值
List<BeanFactoryPostProcessor> BeanFactoryPostProcessor = new ArrayList<>();
public AbstractApplicationContext() {
//引入一個資源解析器
this.resourcePatternResolver = getResourcePatternResolver();
}
protected ResourcePatternResolver getResourcePatternResolver() {
return new PathMatchingResourcePatternResolver(this);
}
3.3 例項化GenericApplicationContext
public GenericApplicationContext() {
//引入BeanFactory實現
this.beanFactory = new DefaultListableBeanFactory();
}
3.4 例項化自己
public AnnotationConfigApplicationContext() {
//初始化基於註解的bean定義掃描器
this.reader = new AnnotatedBeanDefinitionReader(this);
//初始化基於classpath的bean定義掃描器
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
3.4.1 AnnotatedBeanDefinitionReader
初始化過程
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, getOrCreateEnvironment(registry));
}
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
//registry就是我們AnnotationConfigApplicationContext
this.registry = registry;
//引入條件表示式計算器 處理@Conditional註解
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
//註冊所有與註解相關的後置處理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
registerAnnotationConfigProcessors(registry, null);
}
registerAnnotationConfigProcessors(registry, null)
中主要做了以下幾件事情:
-
為
DefaultListableBeanFactory
賦值了兩個引用//依賴排序器,用於處理新增了Priority、Order註解以及實現了Ordered介面的bean beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE); //@Autowire候選解析器 beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
-
往容器中註冊了6個後置處理器的bean定義
註冊配置類的後置處理器
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class); def.setSource(source); registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME);
註冊處理@Autowired註解的後置處理器
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class); def.setSource(source); registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME);
註冊處理@Required註解的後置處理器(5.1版本開始已被廢棄)
RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class); def.setSource(source); registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME);
註冊處理JSR-250規範註解的後置處理器,@Resource,@PostConstruct,@PreDestroy
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class); def.setSource(source); registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME);
註冊處理@EventListener註解的後置處理器
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class); def.setSource(source); registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME);
註冊事件監聽工廠,給上面的EventListenerMethodProcessors使用
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class); def.setSource(source); registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME);
3.4.2 ClassPathBeanDefinitionScanner
初始化過程
經歷了一系列的構造器傳遞
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
this(registry, true);
}
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
this(registry, useDefaultFilters, getOrCreateEnvironment(registry));
}
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment) {
this(registry, useDefaultFilters, environment,
(registry instanceof ResourceLoader ? (ResourceLoader) registry : null));
}
最終實現的構造器方法
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
//預設為true
if (useDefaultFilters) {
//註冊預設的過濾器
registerDefaultFilters();
}
//設定環境
setEnvironment(environment);
//設定資源載入器
setResourceLoader(resourceLoader);
}
registerDefaultFilters
方法
protected void registerDefaultFilters() {
//加入掃描@Component註解的過濾器,這樣就能掃到@Controller,@Service...
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
//JSR-250規範的註解
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
}
catch (ClassNotFoundException ex) {
}
try {
//JSR-330規範的註解
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
}
catch (ClassNotFoundException ex) {
}
}
4. 構造方法執行完畢,執行register(annotatedClasses)
方法,將配置類的bean定義註冊到容器中
public void register(Class<?>... annotatedClasses) {
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
//這裡就使用了剛剛初始化的AnnotatedBeanDefinitionReader掃碼器
//annotatedClasses即為在入口處傳進的自定義配置類Config.class
this.reader.register(annotatedClasses);
}
public void register(Class<?>... annotatedClasses) {
for (Class<?> annotatedClass : annotatedClasses) {
//這裡我們只傳了一個,只有一次迴圈
registerBean(annotatedClass);
}
}
public void registerBean(Class<?> annotatedClass) {
//spring的特點,真正實現的都是do開頭的方法
doRegisterBean(annotatedClass, null, null, null);
}
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
//將class封裝到bean定義中
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
//由於配置類並未使用@Conditional註解,直接返回false
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
abd.setInstanceSupplier(instanceSupplier);
//解析bean定義的作用域
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
//處理普通的bean定義註解,@Lazy @Primary @DependsOn @Role @Description
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
customizer.customize(abd);
}
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
//根據scopeMetadata中的proxy-mode屬性判斷是否需要進行代理封裝,預設否
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
//將bean定義註冊到容器中
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
前期準備工作已基本完畢,可以開始呼叫
refresh
方法啟動IOC容器了。
準備花個30天時間,系統的來整理一下我對spring原始碼的認識:
Spring 原始碼系列
- Spring原始碼分析之 IOC 容器預啟動流程(已完結)
- Spring原始碼分析之BeanFactory體系結構(已完結)
- Spring原始碼分析之BeanFactoryPostProcessor呼叫過程(已完結)
- Spring原始碼分析之Bean的建立過程
- Spring原始碼分析之什麼是迴圈依賴及解決方案
- Spring原始碼分析之AOP從解析到呼叫
- Spring原始碼分析之事務管理(上),事物管理是spring作為容器的一個特點,總結一下他的基本實現與原理吧
- Spring原始碼分析之事務管理(下) ,關於他的底層事物隔離與事物傳播原理,重點分析一下
Spring Mvc 原始碼系列
- SpringMvc體系結構
- SpringMvc原始碼分析之Handler解析過程
- SpringMvc原始碼分析之請求鏈過程
Mybatis 原始碼系列
暫定
追更,可關注我的公眾號:奇客時間,分享純粹為了樂趣,也有一種成就感吧,筆者這篇文章先就到這