目錄
1.環(huán)境和依賴(lài)
1.1.spring boot版本
1.2.依賴(lài)管理
2.自動(dòng)裝配
2.1.流程概述
2.2.三大步前的準(zhǔn)備工作
2.2.1.注解入口
2.2.2.獲取所有配置類(lèi)
2.3.獲取過(guò)濾列表
2.3.1.目的
2.3.2.過(guò)程
2.4.裝載
2.4.1.目的
2.4.2.過(guò)程
2.5.自動(dòng)配置
3.啟動(dòng)過(guò)程
3.1.整體流程
3.2.創(chuàng)建環(huán)境信息對(duì)象
3.3.創(chuàng)建應(yīng)用上下文對(duì)象
3.4.刷新應(yīng)用上下文對(duì)象
3.4.1.準(zhǔn)備刷新
3.4.2.刷新
springboot 2.2.X版本采用的maven構(gòu)建,2.3.X采用gradle構(gòu)建,因此采用2.2.X,mavan構(gòu)建的便于源碼閱讀。本文以2.2.9為例進(jìn)行Spring Boot自動(dòng)裝配原理的解析。
1.2.依賴(lài)管理引入Spring Boot的方式有兩種
這兩種方式的底層都是都是一樣的,都是引入了spring-boot-dependencies這個(gè)pom文件來(lái)管理Spring Boot的所有依賴(lài)。
SpringBoot中將一類(lèi)場(chǎng)景要用到的依賴(lài)封裝成一個(gè)starter,spring-boot-dependencies中包含了J2EE中所有場(chǎng)景(starter)的依賴(lài),并聲明了依賴(lài)的版本號(hào)。
2.自動(dòng)裝配 2.1.流程概述首先所有JAVA程序的入口都是main方法,Spring Boot也不例外,只有main方法執(zhí)行時(shí),所有流程步驟才會(huì)執(zhí)行,此處我們只是從啟動(dòng)流程中剝離出和自動(dòng)裝配相關(guān)的流程來(lái)進(jìn)行單獨(dú)解析。只需要大致知道自動(dòng)裝配流程有幾步即可,如果有其它疑惑看后文的啟動(dòng)過(guò)程解析,就能豁然開(kāi)朗。
自動(dòng)裝配的整個(gè)流程可以分為三大步
1.獲取條件列表
獲取類(lèi)自動(dòng)裝載的條件列表。
2.獲取自動(dòng)配置列表
獲取自動(dòng)裝載類(lèi)的列表。
3.比對(duì)移除、封裝返回
按照條件列表,將不滿(mǎn)足被自動(dòng)裝載條件的類(lèi)移除掉,返回滿(mǎn)足條件的類(lèi)列表。
2.2.三大步前的準(zhǔn)備工作 2.2.1.注解入口@SpringBootApplication
該注解是個(gè)復(fù)合注解:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
@EnableAutoConfiguration啟動(dòng)自動(dòng)裝配:
@Import(AutoConfigurationImportSelector.class)? ,AutoConfigurationImportSelector會(huì)完成所有配置類(lèi)的獲取以及相關(guān)的準(zhǔn)備工作。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}
2.2.2.獲取所有配置類(lèi)AutoConfigurationImportSelector被加載后,經(jīng)過(guò)層層調(diào)用,最終會(huì)調(diào)用到DeferredImportSelector中:
會(huì)去掃描所有@Configuration封裝成一個(gè)列表返回。
public IterablegetImports() {
Iterator var1 = this.deferredImports.iterator();
while(var1.hasNext()) {
ConfigurationClassParser.DeferredImportSelectorHolder deferredImport = (ConfigurationClassParser.DeferredImportSelectorHolder)var1.next();
this.group.process(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getImportSelector());
}
//將得到的自動(dòng)配置類(lèi)按照@order進(jìn)行排序
return this.group.selectImports();
}
2.3.獲取過(guò)濾列表
2.3.1.目的獲取過(guò)濾列表,即去獲取META-INF/spring-autoconfigure-metadata.properties這一文件。這個(gè)文件中會(huì)詳細(xì)記錄Spring Boot自帶的各大J2EE場(chǎng)景的自動(dòng)配置類(lèi)(@Configuration)各自被自動(dòng)裝載生效的前提條件是什么。
2.3.2.過(guò)程DeferredImportSelector.Group.process()中會(huì)首先獲取自動(dòng)裝配的過(guò)濾條件列表,該列表中記錄了待裝配的類(lèi)的裝配條件。獲取的核心方法是getAutoConfigurationMetadata(),該方法會(huì)根據(jù)傳過(guò)來(lái)的ClassLoader去遍歷加載classpath下的所有依賴(lài),獲取依賴(lài)中的META-INF/spring-autoconfigure-metadata.properties文件。
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
() ->String.format("Only %s implementations are supported, got %s",
AutoConfigurationImportSelector.class.getSimpleName(),
deferredImportSelector.getClass().getName()));
//獲取自動(dòng)配置類(lèi)
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
this.autoConfigurationEntries.add(autoConfigurationEntry);
//解析存放自動(dòng)配置類(lèi)
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
private AutoConfigurationMetadata getAutoConfigurationMetadata() {
if (this.autoConfigurationMetadata == null) {
this.autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
}
return this.autoConfigurationMetadata;
}
final class AutoConfigurationMetadataLoader {
protected static final String PATH = "META-INF/spring-autoconfigure-metadata.properties";
private AutoConfigurationMetadataLoader() {
}
static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
return loadMetadata(classLoader, PATH);
}
static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {
try {
Enumerationurls = (classLoader != null) ? classLoader.getResources(path)
: ClassLoader.getSystemResources(path);
Properties properties = new Properties();
while (urls.hasMoreElements()) {
properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement())));
}
return loadMetadata(properties);
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", ex);
}
}
過(guò)濾列表中會(huì)以KV鍵值對(duì)的方式記錄裝配條件,例如:
org.springframework.boot.autoconfigure.amqp.RabbitAnnotationDrivenConfiguration.ConditionalOnClass=org.springframework.amqp.rabbit.annotation.EnableRabbit
2.4.裝載 2.4.1.目的獲取自動(dòng)配置列表
對(duì)比過(guò)濾列表,移除不滿(mǎn)足自動(dòng)裝載的類(lèi)
封裝返回
process()方法中會(huì)調(diào)用getAutoConfigurationEntry()方法,并將過(guò)濾列表傳和ClassLoader傳過(guò)去,在getCandidateConfigurations()方法中通過(guò)傳遞的ClassLoader獲取自動(dòng)裝配的列表"META-INF/spring.factories",然后比對(duì)過(guò)濾列表,將滿(mǎn)足條件的待裝配類(lèi)的全路徑記錄在AutoConfigurationImportSelector.AutoConfigurationGroup的一個(gè)叫autoConfigurationEntries的List中。
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//從spring.factories中加載所有自動(dòng)配置類(lèi)
Listconfigurations = getCandidateConfigurations(annotationMetadata, attributes);
//移除重復(fù)配置類(lèi)
configurations = removeDuplicates(configurations);
//得到指定要移除的類(lèi)(@SpringBootApplication(exclude=FreeMarkerAutoConfiguration.class))
Setexclusions = getExclusions(annotationMetadata, attributes);
//檢查指定要移除的類(lèi),如果不是配置類(lèi),拋出異常
checkExcludedClasses(configurations, exclusions);
//移除指定要移除的自動(dòng)配置類(lèi)
configurations.removeAll(exclusions);
//獲取滿(mǎn)足條件的自動(dòng)配置類(lèi)列表
configurations = filter(configurations, autoConfigurationMetadata);
//記錄下符合條件的對(duì)象,并封裝在實(shí)體中返回
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
一切執(zhí)行完畢后會(huì)回到入口出繼續(xù)向下執(zhí)行this.group.selectImports(),最終會(huì)調(diào)用到AutoConfigurationImportSelector的selectImports()方法,在該方法中會(huì)根據(jù)@order對(duì)自動(dòng)配置類(lèi)進(jìn)行排序。
public IterableselectImports() {
if (this.autoConfigurationEntries.isEmpty()) {
return Collections.emptyList();
}
SetallExclusions = this.autoConfigurationEntries.stream()
.map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());
SetprocessedConfigurations = this.autoConfigurationEntries.stream()
.map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
.collect(Collectors.toCollection(LinkedHashSet::new));
processedConfigurations.removeAll(allExclusions);
return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
.map((importClassName) ->new Entry(this.entries.get(importClassName), importClassName))
.collect(Collectors.toList());
}
2.5.自動(dòng)配置在自動(dòng)裝載步驟中已經(jīng)獲得需要加載的自動(dòng)配置類(lèi)的全路徑,接下來(lái)就是自動(dòng)配置。
以隨便一個(gè)AutoConfiguration類(lèi)為例:
頭上的一大串@Conditional注解其實(shí)就是過(guò)濾時(shí)的過(guò)濾條件,過(guò)濾列表其實(shí)就是通過(guò)這些條件注解生成的。
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(HttpProperties.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {}
這個(gè)@Configuration滿(mǎn)足條件后其中的@Bean都會(huì)被自動(dòng)裝入IOC。
3.啟動(dòng)過(guò)程 3.1.整體流程Spring boot的啟動(dòng)過(guò)程就是圍繞上下文的創(chuàng)建、準(zhǔn)備、刷新(填充)展開(kāi)的。
spring應(yīng)用上下文和servletContext不是一個(gè)東西,servlet上下文用來(lái)維系當(dāng)前應(yīng)用的一塊共享空間,目的是實(shí)現(xiàn)資源和數(shù)據(jù)在應(yīng)用中的全局共享。spring的上下文是一個(gè)維護(hù)Bean定義以及對(duì)象之間協(xié)作關(guān)系的高級(jí)接口,目的是維護(hù)好整個(gè)spring中的資源,如配置文件、Bean對(duì)象等,其涵蓋了IOC,但不只有IOC,可以理解為Spring應(yīng)用的一個(gè)抽象。
在SpringApplication的run()方法中創(chuàng)建應(yīng)用上下文,整個(gè)SpringApplication的run方法主要完成四個(gè)核心動(dòng)作:
prepareEnvironment
創(chuàng)建環(huán)境信息對(duì)象,解析環(huán)境參數(shù),包含配置文件、命令行傳參等。
createApplicationContext
創(chuàng)建應(yīng)用上下文對(duì)象
prepareContext
準(zhǔn)備應(yīng)用上下文對(duì)象
refreshContext
刷新應(yīng)用上下文對(duì)象
// 類(lèi) SpringApplication 代碼片段
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
CollectionexceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
// 包裝通過(guò)命令行傳入的名命令行參數(shù)
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 結(jié)合命令行參數(shù) 準(zhǔn)備環(huán)境對(duì)象,該環(huán)境對(duì)象將會(huì)被設(shè)置到應(yīng)用上下文對(duì)象 ApplicationContext 上 ,
// 環(huán)境對(duì)象通常包含如下信息 :
// 1. profile
// 2. system properties
// 3. system environment
// 4. commandline arguments
// 5. spring 配置文件
// 6. 一個(gè)隨機(jī)值屬性源 random
// 對(duì)于當(dāng)前 WebFlux 應(yīng)用來(lái)講,這里實(shí)現(xiàn)類(lèi)會(huì)使用 StandardReactiveWebEnvironment
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
// 創(chuàng)建應(yīng)用上下文對(duì)象 ApplicationContext
// 實(shí)現(xiàn)類(lèi)會(huì)采用 : AnnotationConfigReactiveWebServerApplicationContext
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 準(zhǔn)備應(yīng)用上下文對(duì)象 ApplicationContext
// 1. 關(guān)聯(lián)環(huán)境信息對(duì)象到應(yīng)用上下文對(duì)象
// 2. 對(duì)象創(chuàng)建后置處理 : 設(shè)置容器的類(lèi)型轉(zhuǎn)換服務(wù)
// 3. 初始化應(yīng)用上下文對(duì)象:調(diào)用各個(gè) ApplicationContextInitializer
// 4. 廣播事件 : ApplicationContextInitializedEvent
// 5. 將應(yīng)用程序參數(shù)作為一個(gè) bean 注冊(cè)到容器 : springApplicationArguments
// 6. 將應(yīng)用程序入口類(lèi)作為 bean 注冊(cè)到容器 (load)
// 7. 上下文加載完成生命周期事件回調(diào),為各個(gè)實(shí)現(xiàn)了 接口 ApplicationContextAware 的
// ApplicationListener 設(shè)置應(yīng)用上下文對(duì)象屬性, 并廣播事件 : ApplicationPreparedEvent
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 刷新應(yīng)用上下文對(duì)象 ApplicationContext
// 主要是調(diào)用應(yīng)用上下文對(duì)象 ApplicationContext 自身的 refresh 方法
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
// 應(yīng)用程序上下文對(duì)象 ApplicationContext 已經(jīng)準(zhǔn)備就緒,
// 現(xiàn)在調(diào)用各種開(kāi)發(fā)人員或者框架其他部分定義的
// ApplicationRunner 或者 CommandLineRunner
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
3.2.創(chuàng)建環(huán)境信息對(duì)象// SpringApplication 代碼片段
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
// 創(chuàng)建環(huán)境信息對(duì)象 environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 將應(yīng)用程序參數(shù)關(guān)聯(lián)到環(huán)境信息對(duì)象 environment
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 發(fā)布應(yīng)用程序事件 : 環(huán)境信息對(duì)象準(zhǔn)備好了 ,
// 同步調(diào)用各個(gè)事件監(jiān)聽(tīng)器
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
普通web應(yīng)用和reactive創(chuàng)建的環(huán)境信息對(duì)象類(lèi)型不同,但是實(shí)際功能相同,并沒(méi)有什么太大區(qū)別。
// SpringApplication 代碼片段
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
switch (this.webApplicationType) {
case SERVLET:
return new StandardServletEnvironment();
case REACTIVE:
return new StandardReactiveWebEnvironment();
default:
return new StandardEnvironment();
}
}
3.3.創(chuàng)建應(yīng)用上下文對(duì)象根據(jù)之前環(huán)境推斷中得到的當(dāng)前應(yīng)用的環(huán)境類(lèi)型來(lái)創(chuàng)建不同類(lèi)型的應(yīng)用上下文。
// SpringApplication 代碼片段
protected ConfigurableApplicationContext createApplicationContext() {
Class>contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
// 根據(jù) this.webApplicationType 確定應(yīng)用上下文實(shí)現(xiàn)類(lèi)
switch (this.webApplicationType) {
case SERVLET:
// DEFAULT_SERVLET_WEB_CONTEXT_CLASS 常量值為 :
// org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
// 對(duì)應(yīng) Spring MVC Servlet Web 環(huán)境
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
// DEFAULT_REACTIVE_WEB_CONTEXT_CLASS 常量值為 :
// org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext
// 對(duì)應(yīng) Spring WebFlux Reactive Web 環(huán)境
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
// DEFAULT_CONTEXT_CLASS 常量值為 :
// org.springframework.context.annotation.AnnotationConfigApplicationContext
// 不對(duì)應(yīng)任何 Web 環(huán)境
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass",
ex);
}
}
// 確定應(yīng)用上下文實(shí)現(xiàn)類(lèi)之后,實(shí)例化應(yīng)用上下文對(duì)象
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
3.4.刷新應(yīng)用上下文對(duì)象
3.4.1.準(zhǔn)備刷新這一步主要是完成刷新前的準(zhǔn)備工作,將除IOC相關(guān)的一切context中的東西全部賦值初始化好。
主要完成以下動(dòng)作:
關(guān)聯(lián)環(huán)境信息
查找調(diào)用各種前置、后置處理器(自定義的、自帶的)
調(diào)用各種回調(diào)
獲取主啟動(dòng)類(lèi)的路徑,將主啟動(dòng)類(lèi)封裝成一個(gè)BeanDefinition
// SpringApplication 代碼片段
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments,
Banner printedBanner) {
// 1. 關(guān)聯(lián)環(huán)境信息對(duì)象到應(yīng)用上下文對(duì)象
context.setEnvironment(environment);
// 2. 對(duì)象創(chuàng)建后置處理 : 設(shè)置容器的類(lèi)型轉(zhuǎn)換服務(wù)
postProcessApplicationContext(context);
// 3. 初始化應(yīng)用上下文對(duì)象:調(diào)用各個(gè) ApplicationContextInitializer
applyInitializers(context);
// 4. 廣播事件 : ApplicationContextInitializedEvent
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
// 5. 將應(yīng)用程序參數(shù)作為一個(gè) bean 注冊(cè)到容器 : springApplicationArguments
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// 獲取主啟動(dòng)類(lèi)的路徑
Set
3.4.2.刷新主要是調(diào)用應(yīng)用上下文對(duì)象 ApplicationContext 自身的 refresh 方法,這是上下文對(duì)象的初始化中最關(guān)鍵的一步,該步驟中會(huì)完成幾個(gè)核心動(dòng)作:
初始化IOC容器(即BeanFactory)
該步驟中就會(huì)掃描解析注解,觸發(fā)自動(dòng)裝配.
初始化WebServer容器
刷新應(yīng)用上下文的動(dòng)作其實(shí)是在spring相關(guān)的jar中,因此首先要有個(gè)概念,在這一步之前spring boot的動(dòng)作已經(jīng)完成,真正與IOC相關(guān)的動(dòng)作還是由spring來(lái)完成,所以說(shuō)spring boot是對(duì)spring的二次封裝。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 做一些初始化動(dòng)作
prepareRefresh();
// 獲取bean factory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 初始化bean factory,為其成員屬性賦一些值
prepareBeanFactory(beanFactory);
try {
// 獲取所有bean后置處理器
postProcessBeanFactory(beanFactory);
// **最核心的方法,注解的掃描,自動(dòng)配置類(lèi)的裝載,IOC的初始化等全在這個(gè)方法中
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();
}
}
}
初始化IOC:
創(chuàng)建容器其實(shí)沒(méi)有什么說(shuō)的,就是new一個(gè)web server(tomcat、netty或者jetty)出來(lái)。這里著重要說(shuō)一下初始化IOC。
入口在invokeBeanFactoryPostProcessors(beanFactory)。
IOC容器的初始化分為三步:
Resource定位
定位到需要的各種路徑:
BasePackage
這一步在準(zhǔn)備刷新的時(shí)候就已經(jīng)完成,并在封裝在了主啟動(dòng)類(lèi)封裝為的BeanDefinition中。
基于BasePackage去掃描通過(guò)注解自定義的需要注入IOC的Bean。
自動(dòng)配置類(lèi)的全路徑
這一步在刷新應(yīng)用上下文的時(shí)候進(jìn)行,即去獲取factory.properties。
基于自動(dòng)配置類(lèi)的全路徑去將對(duì)應(yīng)自動(dòng)配置類(lèi)注入IOC。
BeanDefinition載入
將定位到的Resource記錄的Class分別封裝為一個(gè)個(gè)的Definition。
BeanDefinition注冊(cè)
將Definition注冊(cè)進(jìn)IOC中。其實(shí)就是注入到一個(gè)ConcurrentHashMap中,IOC就是通過(guò)這個(gè)Map來(lái)持有這些BeanDefinition的。
IOC涉及的兩個(gè)核心概念:
BeanDefinition
BeanFactory
IOC容器其實(shí)就是BeanFactory,BeanFactory就是IOC容器的規(guī)范接口,有多個(gè)實(shí)現(xiàn),最典型的就是DefalutListableBeanFactory,IOC容器中有一個(gè)成員Map(BeanDefinitionMap),該Map持有所有的BeanDefinition,用來(lái)維護(hù)Bean的基本信息(class、作用域等)
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧
新聞名稱(chēng):SpringBoot自動(dòng)裝配原理詳解-創(chuàng)新互聯(lián)
分享路徑:http://www.chinadenli.net/article30/gsdpo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站設(shè)計(jì)、網(wǎng)站導(dǎo)航、品牌網(wǎng)站制作、網(wǎng)站維護(hù)、動(dòng)態(tài)網(wǎng)站、自適應(yīng)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容