從Springboot源碼分析啓動過程
這篇博客主要是通過Springboot的源碼,分析Springboot項目的啓動過程,深入理解spring的工作原理。其次,我對部分源碼加上了註解,新手可以稍微看一下,同時我也希望大佬們能指出我理解有誤的地方。
一、springboot啓動源碼解析
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();//項目計時器開始計時
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();//異常處理類集合
configureHeadlessProperty();//設置System全局參數
SpringApplicationRunListeners listeners = getRunListeners(args);//SpringApplicationRunListener.class創建監視器實例
listeners.starting();//發起starting事件(event)
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);//將啓動參數轉換成spring能解析的格式,例如:--foo=bar --foo="tom"
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();//根據webApplicationType的類型創建Context對象實例
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);//準備項目運行的環境,加載xml文件中配置的bean
refreshContext(context);//更新Context 執行用戶定義的postProcessBeanFactory操作,註冊listener相關的bean,初始化所以剩下的單例類
afterRefresh(context, applicationArguments);//用戶自定義的操作
stopWatch.stop();//項目計時器結束計時
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);//打印日誌信息
}
listeners.started(context);//發起ApplicationStartedEvent事件
callRunners(context, applicationArguments);//啓動SpringApplication
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);//發起ApplicationReadyEvent事件
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
二、SpringApplication 類部分源碼解析
/**
* 準備項目運行時的環境變量
* @param listeners 各種監聽器
* @param applicationArguments 參數對象
* @return
*/
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();//初始化environment的Properties和configuration
configureEnvironment(environment, applicationArguments.getSourceArgs());//添加或替換commandLineArgs在environment中的屬性值 確保profile被正確配置
listeners.environmentPrepared(environment);//發起ApplicationEnvironmentPreparedEvent事件
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
/**
* 根據項目類型選擇具體的環境參數類
* @return
*/
private Class<? extends StandardEnvironment> deduceEnvironmentClass() {
switch (this.webApplicationType) {
case SERVLET:
return StandardServletEnvironment.class;
case REACTIVE:
return StandardReactiveWebEnvironment.class;
default:
return StandardEnvironment.class;
}
}
/**
* 初始化項目上下文環境,具體的初始化內容看參數命名就清楚了
* @param context
* @param environment
* @param listeners
* @param applicationArguments
* @param printedBanner
*/
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
/**
* 從spring的資源目錄下加載factory對象的路徑名,資源文件是META-INF/spring.factories
* @param type
* @param parameterTypes
* @param args
* @param <T>
* @return
*/
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));//從spring的資源目錄下加載factory對象的路徑名,資源文件是META-INF/spring.factories
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
/**
* 創建spring各種工廠對象實例 使用classLoader動態加載
* @param type
* @param parameterTypes
* @param classLoader
* @param args
* @param names
* @param <T>
* @return
*/
@SuppressWarnings("unchecked")
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
Set<String> names) {
List<T> instances = new ArrayList<>(names.size());
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass
.getDeclaredConstructor(parameterTypes);//使用Constructor反射類調用有參構造函數創建實例
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException(
"Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
private ConfigurableEnvironment getOrCreateEnvironment() { //配置項目的環境屬性,Note:在java自帶的servlet context初始化之前
if (this.environment != null) {
return this.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);
}
configurePropertySources(environment, args);//添加或替換commandLineArgs在environment中的屬性值
configureProfiles(environment, args);//確保profile被正確配置
}
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug(
"Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
BeanDefinitionLoader loader = createBeanDefinitionLoader(
getBeanDefinitionRegistry(context), sources);//創建一個bean加載器,每個被加載的bean會被自動註冊到cache中
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();
}
以後我會根據啓動過程和你們一起慢慢的解析spring的各種相關的源碼,有機會的話實現一個@EnableXXXX註解,已經實現但是有bug。