springboot原始碼閱讀(一)

啟動過程

springboot原始碼閱讀(一)

1、springboot的入口程式

java

@SpringBootApplication

public class SpringbootApplication {

public static void main(String[] args) {

SpringApplication。run(SpringbootApplication。class, args);

}

}

當程式開始執行之後,會呼叫SpringApplication的構造方法,進行某些初始引數的設定

java

//建立一個新的例項,這個應用程式的上下文將要從指定的來源載入Bean

public SpringApplication(ResourceLoader resourceLoader, Class<?>。。。 primarySources) {

//資源初始化資源載入器,預設為null

this。resourceLoader = resourceLoader;

//斷言主要載入資源類不能為 null,否則報錯

Assert。notNull(primarySources, “PrimarySources must not be null”);

//初始化主要載入資源類集合並去重

this。primarySources = new LinkedHashSet<>(Arrays。asList(primarySources));

//推斷當前 WEB 應用型別,一共有三種:NONE,SERVLET,REACTIVE

this。webApplicationType = WebApplicationType。deduceFromClasspath();

//設定應用上線文初始化器,從“META-INF/spring。factories”讀取ApplicationContextInitializer類的例項名稱集合並去重,並進行set去重。(一共7個)

setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer。class));

//設定監聽器,從“META-INF/spring。factories”讀取ApplicationListener類的例項名稱集合並去重,並進行set去重。(一共11個)

setListeners((Collection) getSpringFactoriesInstances(ApplicationListener。class));

//推斷主入口應用類,通過當前呼叫棧,獲取Main方法所在類,並賦值給mainApplicationClass

this。mainApplicationClass = deduceMainApplicationClass();

}

在上述構造方法中,有一個判斷應用型別的方法,用來判斷當前應用程式的型別:

java

static WebApplicationType deduceFromClasspath() {

if (ClassUtils。isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils。isPresent(WEBMVC_INDICATOR_CLASS, null)

&& !ClassUtils。isPresent(JERSEY_INDICATOR_CLASS, null)) {

return WebApplicationType。REACTIVE;

}

for (String className : SERVLET_INDICATOR_CLASSES) {

if (!ClassUtils。isPresent(className, null)) {

return WebApplicationType。NONE;

}

}

return WebApplicationType。SERVLET;

}

//WebApplicationType的型別

public enum WebApplicationType {

/**

* The application should not run as a web application and should not start an

* embedded web server。

* 非web專案

*/

NONE,

/**

* The application should run as a servlet-based web application and should start an

* embedded servlet web server。

* servlet web 專案

*/

SERVLET,

/**

* The application should run as a reactive web application and should start an

* embedded reactive web server。

* 響應式 web 專案

*/

REACTIVE;

springboot啟動的執行方法,可以看到主要是各種執行環境的準備工作

java

public ConfigurableApplicationContext run(String。。。 args) {

//1、建立並啟動計時監控類

StopWatch stopWatch = new StopWatch();

stopWatch。start();

//2、初始化應用上下文和異常報告集合

ConfigurableApplicationContext context = null;

Collection exceptionReporters = new ArrayList<>();

//3、設定系統屬性“java。awt。headless”的值,預設為true,用於執行headless伺服器,進行簡單的影象處理,多用於在缺少顯示屏、鍵盤或者滑鼠時的系統配置,很多監控工具如jconsole 需要將該值設定為true

configureHeadlessProperty();

//4、建立所有spring執行監聽器併發布應用啟動事件,簡單說的話就是獲取SpringApplicationRunListener型別的例項(EventPublishingRunListener物件),並封裝進SpringApplicationRunListeners物件,然後返回這個SpringApplicationRunListeners物件。說的再簡單點,getRunListeners就是準備好了執行時監聽器EventPublishingRunListener。

SpringApplicationRunListeners listeners = getRunListeners(args);

listeners。starting();

try {

//5、初始化預設應用引數類

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

//6、根據執行監聽器和應用引數來準備spring環境

ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);

//將要忽略的bean的引數開啟

configureIgnoreBeanInfo(environment);

//7、建立banner列印類

Banner printedBanner = printBanner(environment);

//8、建立應用上下文,可以理解為建立一個容器

context = createApplicationContext();

//9、準備異常報告器,用來支援報告關於啟動的錯誤

exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter。class,

new Class[] { ConfigurableApplicationContext。class }, context);

//10、準備應用上下文,該步驟包含一個非常關鍵的操作,將啟動類注入容器,為後續開啟自動化提供基礎

prepareContext(context, environment, listeners, applicationArguments, printedBanner);

//11、重新整理應用上下文

refreshContext(context);

//12、應用上下文重新整理後置處理,做一些擴充套件功能

afterRefresh(context, applicationArguments);

//13、停止計時監控類

stopWatch。stop();

//14、輸出日誌記錄執行主類名、時間資訊

if (this。logStartupInfo) {

new StartupInfoLogger(this。mainApplicationClass)。logStarted(getApplicationLog(), stopWatch);

}

//15、釋出應用上下文啟動監聽事件

listeners。started(context);

//16、執行所有的Runner執行器

callRunners(context, applicationArguments);

}catch (Throwable ex) {

handleRunFailure(context, ex, exceptionReporters, listeners);

throw new IllegalStateException(ex);

}

try {

//17、釋出應用上下文就緒事件

listeners。running(context);

}catch (Throwable ex) {

handleRunFailure(context, ex, exceptionReporters, null);

throw new IllegalStateException(ex);

}

//18、返回應用上下文

return context;

}

下面詳細介紹各個啟動的環節:

1、建立並啟動計時監控類,可以看到記錄當前任務的名稱,預設是空字串,然後記錄當前springboot應用啟動的開始時間。

java

StopWatch stopWatch = new StopWatch();

stopWatch。start();

//詳細原始碼

public void start() throws IllegalStateException {

start(“”);

}

public void start(String taskName) throws IllegalStateException {

if (this。currentTaskName != null) {

throw new IllegalStateException(“Can‘t start StopWatch: it’s already running”);

}

this。currentTaskName = taskName;

this。startTimeNanos = System。nanoTime();

}

2、初始化應用上下文和異常報告集合

java

ConfigurableApplicationContext context = null;

Collection exceptionReporters = new ArrayList<>();

3、設定系統屬性java。awt。headless的值:

java

/*

java。awt。headless模式是在缺少顯示屏、鍵盤或者滑鼠的系統配置

當配置瞭如下屬性之後,應用程式可以執行如下操作:

1、建立輕量級元件

2、收集關於可用的字型、字型指標和字型設定的資訊

3、設定顏色來渲染準備圖片

4、創造和獲取影象,為渲染準備圖片

5、使用java。awt。PrintJob,java。awt。print。*和javax。print。*類裡的方法進行列印

*/

private void configureHeadlessProperty() {

System。setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,

System。getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean。toString(this。headless)));

}

4、建立所有spring執行監聽器併發布應用啟動事件

java

SpringApplicationRunListeners listeners = getRunListeners(args);

listeners。starting();

//建立spring監聽器

private SpringApplicationRunListeners getRunListeners(String[] args) {

Class<?>[] types = new Class<?>[] { SpringApplication。class, String[]。class };

return new SpringApplicationRunListeners(logger,

getSpringFactoriesInstances(SpringApplicationRunListener。class, types, this, args));

}

SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {

this。log = log;

this。listeners = new ArrayList<>(listeners);

}

//迴圈遍歷獲取監聽器

void starting() {

for (SpringApplicationRunListener listener : this。listeners) {

listener。starting();

}

}

//此處的監聽器可以看出是事件釋出監聽器,主要用來發布啟動事件

@Override

public void starting() {

//這裡是建立application事件‘applicationStartingEvent’

this。initialMulticaster。multicastEvent(new ApplicationStartingEvent(this。application, this。args));

}

//applicationStartingEvent是springboot框架最早執行的監聽器,在該監聽器執行started方法時,會繼續釋出事件,主要是基於spring的事件機制

@Override

public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {

ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));

//獲取執行緒池,如果為空則同步處理。這裡執行緒池為空,還未初始化

Executor executor = getTaskExecutor();

for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {

if (executor != null) {

//非同步傳送事件

executor。execute(() -> invokeListener(listener, event));

}

else {

//同步傳送事件

invokeListener(listener, event);

}

}

}

5、初始化預設應用引數類

java

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

public DefaultApplicationArguments(String。。。 args) {

Assert。notNull(args, “Args must not be null”);

this。source = new Source(args);

this。args = args;

}

6、根據執行監聽器和應用引數來準備spring環境

java

ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);

//詳細環境的準備

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,

ApplicationArguments applicationArguments) {

// 獲取或者建立應用環境

ConfigurableEnvironment environment = getOrCreateEnvironment();

// 配置應用環境,配置propertySource和activeProfiles

configureEnvironment(environment, applicationArguments。getSourceArgs());

//listeners環境準備,廣播ApplicationEnvironmentPreparedEvent

ConfigurationPropertySources。attach(environment);

listeners。environmentPrepared(environment);

//將環境繫結給當前應用程式

bindToSpringApplication(environment);

//對當前的環境型別進行判斷,如果不一致進行轉換

if (!this。isCustomEnvironment) {

environment = new EnvironmentConverter(getClassLoader())。convertEnvironmentIfNecessary(environment,

deduceEnvironmentClass());

}

//配置propertySource對它自己的遞迴依賴

ConfigurationPropertySources。attach(environment);

return environment;

}

// 獲取或者建立應用環境,根據應用程式的型別可以分為servlet環境、標準環境(特殊的非web環境)和響應式環境

private ConfigurableEnvironment getOrCreateEnvironment() {

//存在則直接返回

if (this。environment != null) {

return this。environment;

}

//根據webApplicationType建立對應的Environment

switch (this。webApplicationType) {

case SERVLET:

return new StandardServletEnvironment();

case REACTIVE:

return new StandardReactiveWebEnvironment();

default:

return new StandardEnvironment();

}

}

//配置應用環境

protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {

if (this。addConversionService) {

ConversionService conversionService = ApplicationConversionService。getSharedInstance();

environment。setConversionService((ConfigurableConversionService) conversionService);

}

//配置property sources

configurePropertySources(environment, args);

//配置profiles

configureProfiles(environment, args);

}

7、建立banner的列印類

java

Banner printedBanner = printBanner(environment);

//列印類的詳細操作過程

private Banner printBanner(ConfigurableEnvironment environment) {

if (this。bannerMode == Banner。Mode。OFF) {

return null;

}

ResourceLoader resourceLoader = (this。resourceLoader != null) ? this。resourceLoader

: new DefaultResourceLoader(getClassLoader());

SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this。banner);

if (this。bannerMode == Mode。LOG) {

return bannerPrinter。print(environment, this。mainApplicationClass, logger);

}

return bannerPrinter。print(environment, this。mainApplicationClass, System。out);

}

8、建立應用的上下文:根據不同哦那個的應用型別初始化不同的上下文應用類

java

context = createApplicationContext();

protected ConfigurableApplicationContext createApplicationContext() {

Class<?> contextClass = this。applicationContextClass;

if (contextClass == null) {

try {

switch (this。webApplicationType) {

case SERVLET:

contextClass = Class。forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);

break;

case REACTIVE:

contextClass = Class。forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);

break;

default:

contextClass = Class。forName(DEFAULT_CONTEXT_CLASS);

}

}

catch (ClassNotFoundException ex) {

throw new IllegalStateException(

“Unable create a default ApplicationContext, please specify an ApplicationContextClass”, ex);

}

}

return (ConfigurableApplicationContext) BeanUtils。instantiateClass(contextClass);

}

9、準備異常報告器

java

exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter。class,

new Class[] { ConfigurableApplicationContext。class }, context);

private Collection getSpringFactoriesInstances(Class type, Class<?>[] parameterTypes, Object。。。 args) {

ClassLoader classLoader = getClassLoader();

// Use names and ensure unique to protect against duplicates

Set names = new LinkedHashSet<>(SpringFactoriesLoader。loadFactoryNames(type, classLoader));

List instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);

AnnotationAwareOrderComparator。sort(instances);

return instances;

}

10、準備應用上下文

java

prepareContext(context, environment, listeners, applicationArguments, printedBanner);

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,

SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {

//應用上下文的environment

context。setEnvironment(environment);

//應用上下文後處理

postProcessApplicationContext(context);

//為上下文應用所有初始化器,執行容器中的applicationContextInitializer(spring。factories的例項),將所有的初始化物件放置到context物件中

applyInitializers(context);

//觸發所有SpringApplicationRunListener監聽器的ContextPrepared事件方法。新增所有的事件監聽器

listeners。contextPrepared(context);

//記錄啟動日誌

if (this。logStartupInfo) {

logStartupInfo(context。getParent() == null);

logStartupProfileInfo(context);

}

// 註冊啟動引數bean,將容器指定的引數封裝成bean,注入容器

ConfigurableListableBeanFactory beanFactory = context。getBeanFactory();

beanFactory。registerSingleton(“springApplicationArguments”, applicationArguments);

//設定banner

if (printedBanner != null) {

beanFactory。registerSingleton(“springBootBanner”, printedBanner);

}

if (beanFactory instanceof DefaultListableBeanFactory) {

((DefaultListableBeanFactory) beanFactory)

。setAllowBeanDefinitionOverriding(this。allowBeanDefinitionOverriding);

}

if (this。lazyInitialization) {

context。addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());

}

// 載入所有資源,指的是啟動器指定的引數

Set sources = getAllSources();

Assert。notEmpty(sources, “Sources must not be empty”);

//將bean載入到上下文中

load(context, sources。toArray(new Object[0]));

//觸發所有springapplicationRunListener監聽器的contextLoaded事件方法,

listeners。contextLoaded(context);

}

——————————-

//這裡沒有做任何的處理過程,因為beanNameGenerator和resourceLoader預設為空,可以方便後續做擴充套件處理

protected void postProcessApplicationContext(ConfigurableApplicationContext context) {

if (this。beanNameGenerator != null) {

context。getBeanFactory()。registerSingleton(AnnotationConfigUtils。CONFIGURATION_BEAN_NAME_GENERATOR,

this。beanNameGenerator);

}

if (this。resourceLoader != null) {

if (context instanceof GenericApplicationContext) {

((GenericApplicationContext) context)。setResourceLoader(this。resourceLoader);

}

if (context instanceof DefaultResourceLoader) {

((DefaultResourceLoader) context)。setClassLoader(this。resourceLoader。getClassLoader());

}

}

if (this。addConversionService) {

context。getBeanFactory()。setConversionService(ApplicationConversionService。getSharedInstance());

}

}

——————————-

//將啟動器類載入到spring容器中,為後續的自動化配置奠定基礎,之前看到的很多註解也與此相關

protected void load(ApplicationContext context, Object[] sources) {

if (logger。isDebugEnabled()) {

logger。debug(“Loading source ” + StringUtils。arrayToCommaDelimitedString(sources));

}

BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);

if (this。beanNameGenerator != null) {

loader。setBeanNameGenerator(this。beanNameGenerator);

}

if (this。resourceLoader != null) {

loader。setResourceLoader(this。resourceLoader);

}

if (this。environment != null) {

loader。setEnvironment(this。environment);

}

loader。load();

}

——————————-

//springboot會優先選擇groovy載入方式,找不到在選擇java方式

private int load(Class<?> source) {

if (isGroovyPresent() && GroovyBeanDefinitionSource。class。isAssignableFrom(source)) {

// Any GroovyLoaders added in beans{} DSL can contribute beans here

GroovyBeanDefinitionSource loader = BeanUtils。instantiateClass(source, GroovyBeanDefinitionSource。class);

load(loader);

}

if (isComponent(source)) {

this。annotatedReader。register(source);

return 1;

}

return 0;

}

11、重新整理應用上下文

java

refreshContext(context);

private void refreshContext(ConfigurableApplicationContext context) {

refresh(context);

if (this。registerShutdownHook) {

try {

context。registerShutdownHook();

}

catch (AccessControlException ex) {

// Not allowed in some environments。

}

}

}

——————

public void refresh() throws BeansException, IllegalStateException {

synchronized (this。startupShutdownMonitor) {

// Prepare this context for refreshing。

//重新整理上下文環境,初始化上下文環境,對系統的環境變數或者系統屬性進行準備和校驗

prepareRefresh();

// Tell the subclass to refresh the internal bean factory。

//初始化beanfactory,解析xml,相當於之前的xmlBeanfactory操作

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context。

//為上下文準備beanfactory,對beanFactory的各種功能進行填充,如@autowired,設定spel表示式解析器,設定編輯註冊器,新增applicationContextAwareprocessor處理器等等

prepareBeanFactory(beanFactory);

try {

// Allows post-processing of the bean factory in context subclasses。

//提供子類覆蓋的額外處理,即子類處理自定義的beanfactorypostProcess

postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context。

//啟用各種beanfactory處理器

invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation。

//註冊攔截bean建立的bean處理器,即註冊beanPostProcessor

registerBeanPostProcessors(beanFactory);

// Initialize message source for this context。

//初始化上下文中的資原始檔如國際化檔案的處理

initMessageSource();

// Initialize event multicaster for this context。

//初始化上下文事件廣播器

initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses。

//給子類擴充套件初始化其他bean

onRefresh();

// Check for listener beans and register them。

//在所有的bean中查詢listener bean,然後 註冊到廣播器中

registerListeners();

// Instantiate all remaining (non-lazy-init) singletons。

//初始化剩餘的非懶惰的bean,即初始化非延遲載入的bean

finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event。

//發完成重新整理過程,通知宣告週期處理器重新整理過程,同時發出ContextRefreshEvent通知別人

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();

}

}

}

12、應用上下文重新整理後置處理

java

afterRefresh(context, applicationArguments);

//當前方法的程式碼是空的,可以做一些自定義的後置處理操作

protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {

}

13、停止計時監控類:計時監聽器停止,並統計一些任務執行資訊

java

stopWatch。stop();

public void stop() throws IllegalStateException {

if (this。currentTaskName == null) {

throw new IllegalStateException(“Can’t stop StopWatch: it‘s not running”);

}

long lastTime = System。nanoTime() - this。startTimeNanos;

this。totalTimeNanos += lastTime;

this。lastTaskInfo = new TaskInfo(this。currentTaskName, lastTime);

if (this。keepTaskList) {

this。taskList。add(this。lastTaskInfo);

}

++this。taskCount;

this。currentTaskName = null;

}

14、輸出日誌記錄執行主類名、時間資訊

java

if (this。logStartupInfo) {

new StartupInfoLogger(this。mainApplicationClass)。logStarted(getApplicationLog(), stopWatch);

}

15、釋出應用上下文啟動完成事件:觸發所有SpringapplicationRunListener監聽器的started事件方法

java

listeners。started(context);

void started(ConfigurableApplicationContext context) {

for (SpringApplicationRunListener listener : this。listeners) {

listener。started(context);

}

}

16、執行所有Runner執行器:執行所有applicationRunner和CommandLineRunner兩種執行器

java

callRunners(context, applicationArguments);

private void callRunners(ApplicationContext context, ApplicationArguments args) {

List runners = new ArrayList<>();

runners。addAll(context。getBeansOfType(ApplicationRunner。class)。values());

runners。addAll(context。getBeansOfType(CommandLineRunner。class)。values());

AnnotationAwareOrderComparator。sort(runners);

for (Object runner : new LinkedHashSet<>(runners)) {

if (runner instanceof ApplicationRunner) {

callRunner((ApplicationRunner) runner, args);

}

if (runner instanceof CommandLineRunner) {

callRunner((CommandLineRunner) runner, args);

}

}

}

17、釋出應用上下文就緒事件:觸發所有springapplicationRunnListener將挺起的running事件方法

java

listeners。running(context);

void running(ConfigurableApplicationContext context) {

for (SpringApplicationRunListener listener : this。listeners) {

listener。running(context);

}

}

18、返回應用上下文

java

return context;

————————————————————————————————————-

注意:

整個springboot框架中獲取factorys檔案的方式統一如下:

java

private Collection getSpringFactoriesInstances(Class type) {

return getSpringFactoriesInstances(type, new Class<?>[] {});

}

——————————————————-

private Collection getSpringFactoriesInstances(Class type, Class<?>[] parameterTypes, Object。。。 args) {

ClassLoader classLoader = getClassLoader();

// Use names and ensure unique to protect against duplicates

Set names = new LinkedHashSet<>(SpringFactoriesLoader。loadFactoryNames(type, classLoader));

List instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);

AnnotationAwareOrderComparator。sort(instances);

return instances;

}

——————————————-

public static List loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {

String factoryTypeName = factoryType。getName();

return loadSpringFactories(classLoader)。getOrDefault(factoryTypeName, Collections。emptyList());

}

private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {

MultiValueMap result = cache。get(classLoader);

if (result != null) {

return result;

}

try {

Enumeration urls = (classLoader != null ?

classLoader。getResources(FACTORIES_RESOURCE_LOCATION) :

ClassLoader。getSystemResources(FACTORIES_RESOURCE_LOCATION));

result = new LinkedMultiValueMap<>();

while (urls。hasMoreElements()) {

URL url = urls。nextElement();

UrlResource resource = new UrlResource(url);

Properties properties = PropertiesLoaderUtils。loadProperties(resource);

for (Map。Entry<?, ?> entry : properties。entrySet()) {

String factoryTypeName = ((String) entry。getKey())。trim();

for (String factoryImplementationName : StringUtils。commaDelimitedListToStringArray((String) entry。getValue())) {

result。add(factoryTypeName, factoryImplementationName。trim());

}

}

}

cache。put(classLoader, result);

return result;

}

catch (IOException ex) {

throw new IllegalArgumentException(“Unable to load factories from location [” +

FACTORIES_RESOURCE_LOCATION + “]”, ex);

}

}

————————————-

private List createSpringFactoriesInstances(Class type, Class<?>[] parameterTypes,

ClassLoader classLoader, Object[] args, Set names) {

List instances = new ArrayList<>(names。size());

for (String name : names) {

try {

//裝載class檔案到記憶體

Class<?> instanceClass = ClassUtils。forName(name, classLoader);

Assert。isAssignable(type, instanceClass);

Constructor<?> constructor = instanceClass。getDeclaredConstructor(parameterTypes);

//透過反射建立例項

T instance = (T) BeanUtils。instantiateClass(constructor, args);

instances。add(instance);

}

catch (Throwable ex) {

throw new IllegalArgumentException(“Cannot instantiate ” + type + “ : ” + name, ex);

}

}

return instances;

}

spring。factory檔案中的類的作用:

properties

# PropertySource Loaders 屬性檔案載入器

org。springframework。boot。env。PropertySourceLoader=\

# properties檔案載入器

org。springframework。boot。env。PropertiesPropertySourceLoader,\

# yaml檔案載入器

org。springframework。boot。env。YamlPropertySourceLoader

# Run Listeners 執行時的監聽器

org。springframework。boot。SpringApplicationRunListener=\

# 程式執行過程中所有監聽通知都是透過此類來進行回撥

org。springframework。boot。context。event。EventPublishingRunListener

# Error Reporters 錯誤報告器

org。springframework。boot。SpringBootExceptionReporter=\

org。springframework。boot。diagnostics。FailureAnalyzers

# Application Context Initializers

org。springframework。context。ApplicationContextInitializer=\

# 報告spring容器的一些常見的錯誤配置

org。springframework。boot。context。ConfigurationWarningsApplicationContextInitializer,\

# 設定spring應用上下文的ID

org。springframework。boot。context。ContextIdApplicationContextInitializer,\

# 使用環境屬性context。initializer。classes指定初始化器進行初始化規則

org。springframework。boot。context。config。DelegatingApplicationContextInitializer,\

org。springframework。boot。rsocket。context。RSocketPortInfoApplicationContextInitializer,\

# 將內建servlet容器實際使用的監聽埠寫入到environment環境屬性中

org。springframework。boot。web。context。ServerPortInfoApplicationContextInitializer

# Application Listeners

org。springframework。context。ApplicationListener=\

# 應用上下文載入完成後對快取做清除工作,響應事件ContextRefreshEvent

org。springframework。boot。ClearCachesApplicationListener,\

# 監聽雙親應用上下文的關閉事件並往自己的孩子應用上下文中傳播,相關事件ParentContextAvailableEvent/ContextClosedEvent

org。springframework。boot。builder。ParentContextCloserApplicationListener,\

org。springframework。boot。cloud。CloudFoundryVcapEnvironmentPostProcessor,\

# 如果系統檔案編碼和環境變數中指定的不同則終止應用啟動。具體的方法是比較系統屬性file。encoding和環境變數spring。mandatory-file-encoding是否相等(大小寫不敏感)。

org。springframework。boot。context。FileEncodingApplicationListener,\

# 根據spring。output。ansi。enabled引數配置AnsiOutput

org。springframework。boot。context。config。AnsiOutputApplicationListener,\

# EnvironmentPostProcessor,從常見的那些約定的位置讀取配置檔案,比如從以下目錄讀取#application。properties,application。yml等配置檔案:

# classpath:

# file:。

# classpath:config

# file:。/config/:

# 也可以配置成從其他指定的位置讀取配置檔案

org。springframework。boot。context。config。ConfigFileApplicationListener,\

# 監聽到事件後轉發給環境變數context。listener。classes指定的那些事件監聽器

org。springframework。boot。context。config。DelegatingApplicationListener,\

# 一個SmartApplicationListener,對環境就緒事件ApplicationEnvironmentPreparedEvent/應用失敗事件ApplicationFailedEvent做出響應,往日誌DEBUG級別輸出TCCL(thread context class loader)的classpath。

org。springframework。boot。context。logging。ClasspathLoggingApplicationListener,\

# 檢測正在使用的日誌系統,預設是logback,,此時日誌系統還沒有初始化

org。springframework。boot。context。logging。LoggingApplicationListener,\

# 使用一個可以和Spring Boot可執行jar包配合工作的版本替換liquibase ServiceLocator

org。springframework。boot。liquibase。LiquibaseServiceLocatorApplicationListener

頭條長度受限,可以去開源中國、或者CSDN