SpringBoot启动源码
前言
开始之前,需要先了解下springboot的SPI
SPI 与 API的区别
SPI : 我提供接口,你实现,我来调用你
API: 我提供接口和实现, 你来调我
getSpringFactoriesInstances
一定 牢记 这个方法(Springboot的SPI)
- 获取类加载器,默认是应用类加载器
- 读取spring.factories 配置的 type类型的 接口实现的全类名,放入set集合
- 将这些类实例化
- 根据Order排序,升序
java
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
// 获取类加载器,默认是应用类加载器
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
// 读取spring.factories 配置的 type类型的 接口实现,放入set集合
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 将这些类实例化
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
// 根据order接口排序,如果没有实现Order接口,则根据@Order注解排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
loadFactoryNames
获取当前类加载器 加载的classpath下的 spring.factories 将文件内容转为Map<String, List>,key为 接口的全类名,value为对应实现类的全类名
java
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
// 获取当前类加载器加载的spring.factories
Map<String, List<String>> result = cache.get(classLoader);
if (result != null) {
return result;
}
result = new HashMap<>();
try {
// 加载classpath下面的所有META-INF/spring.factories
Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
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();
// 接口对应实现的全类名,用,分割
String[] factoryImplementationNames =
StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
for (String factoryImplementationName : factoryImplementationNames) {
result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
.add(factoryImplementationName.trim());
}
}
}
// 去重并收集为 不可修改的列表
// Replace all lists with unmodifiable lists containing unique elements
result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
// 缓存
cache.put(classLoader, result);
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
return result;
}
createSpringFactoriesInstances
- 根据classLoader 获取 Class对象
- 获取无参构造函数
- 无参构造实例化
- 返回所有实例化对象
java
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对象
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
// parameterTypes 和 args 是上面调用传来的构造参数,都是空
// 所以这里获取 无参构造函数(必须有无参构造函数)
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;
}
AnnotationAwareOrderComparator.sort(instances)
对实例化对象进行Order排序,确定后续的执行顺序
- 先获取Order接口返回的值
- 如果没有实现Order接口,获取@Order注解返回的值
- 默认Order是Integer的最大值
- 安装Order升序排列
java
public class AnnotationAwareOrderComparator extends OrderComparator {
/**
* Shared default instance of {@code AnnotationAwareOrderComparator}.
*/
public static final AnnotationAwareOrderComparator INSTANCE = new AnnotationAwareOrderComparator();
@Override
@Nullable
// 先获取Order接口返回的值
// 如果没有实现Order接口,获取@Order注解返回的值
// 默认Order是Integer的最大值
// 安装Order升序排列
protected Integer findOrder(Object obj) {
Integer order = super.findOrder(obj);
if (order != null) {
return order;
}
return findOrderFromAnnotation(obj);
}
@Nullable
private Integer findOrderFromAnnotation(Object obj) {
AnnotatedElement element = (obj instanceof AnnotatedElement ? (AnnotatedElement) obj : obj.getClass());
MergedAnnotations annotations = MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY);
Integer order = OrderUtils.getOrderFromAnnotations(element, annotations);
if (order == null && obj instanceof DecoratingProxy) {
return findOrderFromAnnotation(((DecoratingProxy) obj).getDecoratedClass());
}
return order;
}
// 排序入口
public static void sort(List<?> list) {
if (list.size() > 1) {
list.sort(INSTANCE);
}
}
.....
}
启动入口
java
@SpringBootApplication
public class MyAppApplication {
public static void main(String[] args) {
SpringApplication.run(MyAppApplication.class, args);
}
}
内部调用逻辑
- 创建 SpringApplication 对象
- 调用run方法
java
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
创建SpringApplication 对象
- 判断是什么web应用(MVC,WebFlux,None)
- 设置一些初始化对象
- 获取启动类的class对象(main函数所在位置)
java
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// this.resourceLoader = null
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 判断是什么web类型的应用
// 有 WebFlux 没有 Spring MVC 没有 Jersey ⇒ 这是一个"纯 WebFlux 应用
// 缺少 servlet 或 ConfigurableWebApplicationContext ⇒ 这是一个普通应用(非WEB)
// 否则 是 MVC 的 web应用
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 赋值 bootstrap初始化器
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
// 设置初始化器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 设置监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 根据调用栈信息,获取当前启动类的class对象
this.mainApplicationClass = deduceMainApplicationClass();
}
启动运行
- 构建bootstrap上下文
- 准备环境信息
- 构建Application上下文
- 注册上下文中的bean信息
启动过程中穿插着一些Listeners 的 事件传播
java
public ConfigurableApplicationContext run(String... args) {
// 获取开始时间
long startTime = System.nanoTime();
// 创建默认的bootstrap上下文,并执行bootstrap的初始化器
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
// 根据系统参数获取 java.awt.headless,是否有图形显示
configureHeadlessProperty();
// 获取 SpringApplicationRunListener 监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
// 执行监听器的内容
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 准备环境信息
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
configureIgnoreBeanInfo(environment);
// 打印 springboot的标志和版本
Banner printedBanner = printBanner(environment);
// 创建spring上下文
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
// 准备上下文
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 刷新上下文
refreshContext(context);
// 这是留的一个模板方法,默认是空方法
// 留给SpringApplication的子类实现
afterRefresh(context, applicationArguments);
// 计算启动花费时间
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
// 发送springboot工程已启动的事件
listeners.started(context, timeTakenToStartup);
// 调用根据Order排序后的 ApplicationRunner 和 CommandLineRunner,执行启动后的一些处理
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
// 发送springboot工程已就绪的事件
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
}
catch (Throwable ex) {
// 出现异常,执行异常处理
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
prepareEnvironment
准备环境配置信息 优先级为
- commandLineArgs(优先级永远最高)
- systemProperties
- systemEnvironment
- defaultProperties (优先级永远最低)
java
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// Create and configure the environment
// 根据web类型创建环境信息
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置环境信息(defaultProperties,commandLineArgs)
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 配置环境信息 configurationProperties (包含上面所有的参数)
ConfigurationPropertySources.attach(environment);
// 监听器执行环境准备(实际是发送环境准备完成的事件)
listeners.environmentPrepared(bootstrapContext, environment);
// 将默认配置移动到最后(优先级最低)
DefaultPropertiesPropertySource.moveToEnd(environment);
Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
"Environment prefix cannot be set via properties.");
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
prepareContext
根据SpringApplication.run()方法中传入的启动配置类,加载出上下文信息 并将启动类放入Spring容器
java
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
// 上下文后置处理
postProcessApplicationContext(context);
// 执行 初始化器 ApplicationContextInitializer
applyInitializers(context);
// 监听器发送 上下文准备的事件
listeners.contextPrepared(context);
// 发送一个bootstrap close事件
bootstrapContext.close(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 注册springApplicationArguments bean ,内部存储args内容(会解析 --xxx=aa 、 bb)
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
// 允许循环引用
((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
if (beanFactory instanceof DefaultListableBeanFactory) {
// 允许bean覆盖
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
}
// springboot默认加载全部bean,这里默认为false
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// 添加bean工厂的后置处理器(保证defaultProperties 优先级最低)
context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
// Load the sources
// 加载Application启动类配置
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
// 监听器发送 上下文已加载的事件
listeners.contextLoaded(context);
}
refreshContext
这里就是Spring的启动代码
完成一些列bean的注册
这里就不再解释了
java
private void refreshContext(ConfigurableApplicationContext context) {
if (this.registerShutdownHook) {
shutdownHook.registerApplicationContext(context);
}
refresh(context);
}
protected void refresh(ConfigurableApplicationContext applicationContext) {
applicationContext.refresh();
}
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
// 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();
contextRefresh.end();
}
}
}