从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。