1.概览
我们在创建一个springBoot项目的时候,默认给了一个启动类DemoApplication
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
其中组合注解@SpringBootApplication是一键启动的核心:
@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 {
...
}
这个注解上几种注解的含义如下
- @Target (ElementType.TYPE):元注解之一,表明该注解是用在类、接口、枚举类上的。
- @Retention(RetentionPolicy.RUNTIME):元注解之一,表示该注解是运行时注解,在项目运行时也保留了这个注解。
- @Documented:元注解之一,表示该类在生成帮助文档时,这个注解会被保留。
- @Inherited:元注解之一,标识这个注解是可以被子类继承的。
- @SpringBootConfiguration:组合注解,效果等同于@Configuration,声明该类是个配置类。
- @EnableAutoConfiguration:组合注解,提供自动将带有@Configuration注解配置的bean都初始化到IOC容器中。
- @ComponentScan: 组合注解,由于声明哪些包中的类需要被扫描到,excludeFilters 参数是排除掉过滤器匹配到的类。
启动类不加这个注解@SpringBootApplication,一般的springBoot项目也可以run成功,但是扫描不到其他包下的Bean。如果配置了Spring-Web。他会报找不到ServletWebServerFactory这个类,就是因为没有自动扫描依赖包的原因。
我们按照springboot-Web项目启动运行的加载顺序去理清整套流程。 在DemoApplication 类的main方法中调用了静态方法run,该方法就是创建了一个SpringApplication实例并运行run方法。
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
SpringApplication的构造参数如下:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 资源加载器,默认为null
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// 这地方primarySources就是我们的启动类
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 根据classpath中的存在的类推断应用类型(REACTIVE、SERVLET、NONE)
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 从Spring.Factories文件中加载bootstrapRegistryInitializer
this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
// 从Spring.Factories文件中加载ApplicationContextInitializer集合
setInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 从Spring.Factories文件中加载ApplicationListener集合
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//推断主类
this.mainApplicationClass = deduceMainApplicationClass();
}
run方法如下:
public ConfigurableApplicationContext run(String... args) {
// 1.创建一个计时器记录启动耗时
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 3.创建引导上下文
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
// 定义一个可配置的应用上下文对象,ConfigurableApplicationContext下实现了所有类型的应用上下文
ConfigurableApplicationContext context = null;
// 设置java.awt.headless值,为true时表明缺少显示屏、键盘或者鼠标
configureHeadlessProperty();
//4. 获取运行时监听器集合
SpringApplicationRunListeners listeners = getRunListeners(args);
// 启动监听器
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// 获取启动时的应用参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 5.准备配置环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// 配置spring.beaninfo.ignore值
configureIgnoreBeanInfo(environment);
// 6.打印启动横幅
Banner printedBanner = printBanner(environment);
// 7.根据项目创建上下文
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
// 8.准备上下文
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 9.刷新上下文,项目启动完成
refreshContext(context);
// 10.刷新后的后置处理
afterRefresh(context, applicationArguments);
// 耗时打印
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
// 监听器监听上下文启动完成
listeners.started(context);
// 调用实现ApplicationRunner或CommandLineRunner的一些自定义操作,默认没有
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
...
}
try {
// 监听器监听上下文运行
listeners.running(context);
}
catch (Throwable ex) {
...
}
return context;
}
接下来,我们一步步的看run中涉及到的点:
2.创建计时器:StopWatch
StopWatch是org.springframework.util 带的一个计时器,一般会又来记录时间。具体用法可以参考:goodlymoon.com/archives/11…
3.创建引导上下文:DefaultBootstrapContext
该部分会生成一个DefaultBootstrapContext 对象,他实现了接口BootstrapRegistry和BootstrapContext,这个接口是用于注册一些用来共享或者创建成本较大的对象实例。保证这些实例在应用上下文创建完成之前可以使用。
public class DefaultBootstrapContext implements ConfigurableBootstrapContext {
// InstanceSupplier接口的map,InstanceSupplier是个函数式接口,可以生产对应泛型的对象数据
private final Map<Class<?>, InstanceSupplier<?>> instanceSuppliers = new HashMap<>();
// 具体实例对象的map,当InstanceSupplier对象对象属性是SCOPE时,将InstanceSupplier接口的对象放入该Map
private final Map<Class<?>, Object> instances = new HashMap<>();
// 事件广播器
private final ApplicationEventMulticaster events = new SimpleApplicationEventMulticaster();
// 注册函数接口
@Override
public <T> void register(Class<T> type, InstanceSupplier<T> instanceSupplier) {
register(type, instanceSupplier, true);
}
// 注册函数接口
@Override
public <T> void registerIfAbsent(Class<T> type, InstanceSupplier<T> instanceSupplier) {
register(type, instanceSupplier, false);
}
// 注册到instanceSuppliers
private <T> void register(Class<T> type, InstanceSupplier<T> instanceSupplier, boolean replaceExisting) {
Assert.notNull(type, "Type must not be null");
Assert.notNull(instanceSupplier, "InstanceSupplier must not be null");
synchronized (this.instanceSuppliers) {
boolean alreadyRegistered = this.instanceSuppliers.containsKey(type);
if (replaceExisting || !alreadyRegistered) {
Assert.state(!this.instances.containsKey(type), () -> type.getName() + " has already been created");
this.instanceSuppliers.put(type, instanceSupplier);
}
}
}
// 判断类是否已经注册到instanceSuppliers
@Override
public <T> boolean isRegistered(Class<T> type) {
synchronized (this.instanceSuppliers) {
return this.instanceSuppliers.containsKey(type);
}
}
// 获取泛型对象的函数接口
@Override
@SuppressWarnings("unchecked")
public <T> InstanceSupplier<T> getRegisteredInstanceSupplier(Class<T> type) {
synchronized (this.instanceSuppliers) {
return (InstanceSupplier<T>) this.instanceSuppliers.get(type);
}
}
// 添加BootstrapContextClosedEvent事件监听器
@Override
public void addCloseListener(ApplicationListener<BootstrapContextClosedEvent> listener) {
this.events.addApplicationListener(listener);
}
// 获取泛型对象
@Override
public <T> T get(Class<T> type) throws IllegalStateException {
return getOrElseThrow(type, () -> new IllegalStateException(type.getName() + " has not been registered"));
}
// 获取泛型对象
@Override
public <T> T getOrElse(Class<T> type, T other) {
return getOrElseSupply(type, () -> other);
}
// 获取泛型对象
@Override
public <T> T getOrElseSupply(Class<T> type, Supplier<T> other) {
synchronized (this.instanceSuppliers) {
InstanceSupplier<?> instanceSupplier = this.instanceSuppliers.get(type);
return (instanceSupplier != null) ? getInstance(type, instanceSupplier) : other.get();
}
}
// 获取泛型对象
@Override
public <T, X extends Throwable> T getOrElseThrow(Class<T> type, Supplier<? extends X> exceptionSupplier) throws X {
synchronized (this.instanceSuppliers) {
InstanceSupplier<?> instanceSupplier = this.instanceSuppliers.get(type);
if (instanceSupplier == null) {
throw exceptionSupplier.get();
}
return getInstance(type, instanceSupplier);
}
}
// 获取泛型对象
@SuppressWarnings("unchecked")
private <T> T getInstance(Class<T> type, InstanceSupplier<?> instanceSupplier) {
T instance = (T) this.instances.get(type);
if (instance == null) {
instance = (T) instanceSupplier.get(this);
if (instanceSupplier.getScope() == Scope.SINGLETON) {
this.instances.put(type, instance);
}
}
return instance;
}
/**
* Method to be called when {@link BootstrapContext} is closed and the
* {@link ApplicationContext} is prepared.
* @param applicationContext the prepared context
*/
// 该方法会在BootstrapContext上下文关闭,ApplicationContext准备好的时候调用,广播一个BootstrapContextClosedEvent事件
public void close(ConfigurableApplicationContext applicationContext) {
this.events.multicastEvent(new BootstrapContextClosedEvent(this, applicationContext));
}
}
DefaultBootstrapContext 类中有一个对象:applicationEventMulticaster是一个事件广播器接口。这个接口可以管理很多个ApplicationListener对象。并将事件发布给这些监听器。它是一个标准的观察者模式,对于他内部的监听者applicationListeners,每次事件到来都会一一获取通知。
4.获取监听器集合:SpringApplicationRunListeners
在获取监听器之前,它定义了一个ConfigurableApplicationContext 上下文接口(该接口是众多上下文实现类的父接口:可以参考juejin.cn/post/700332… ,里面对IOC容器架构有一个统一的描述)
之后,我们深入研究一下getRunListeners方法:
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
// 构建一个新的SpringApplicationRunListeners类,对象listeners 从getSpringFactoriesInstances方法中获取SpringApplicationRunListener接口的实现类集合
return new SpringApplicationRunListeners(logger,getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup);
}
/**
* 通过spring 的SpringFactories机制,去获取META-INF/spring.factories配置中type类型对应的接口实现类
**/
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
// 从loadFactoryNames方法获取type对应的实现类名称集合
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
在该方法中通过SpringFactories机制,去获取META-INF/spring.factories配置中type类型对应的接口实现类。通过spring-boot.jar包下META-INF/spring.factories文件可以看到SpringApplicationRunListener.class对应的实现类是org.springframework.boot.context.event.EventPublishingRunListener
最终监听器集合SpringApplicationRunListeners对象获取到的监听器只包含EventPublishingRunListener这一个。
5.配置环境准备:ConfigurableEnvironment
// listeners和bootstrapContext是创建的监听器集合和启动上下文,applicationArguments是应用程序启动参数
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
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) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
// 根据SpringApplication对象构造时获取的webApplicationType选择上下文环境
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
switch (this.webApplicationType) {
case SERVLET:
return new ApplicationServletEnvironment();
case REACTIVE:
return new ApplicationReactiveWebEnvironment();
default:
return new ApplicationEnvironment();
}
}
在web项目中,返回的ConfigurableEnvironment实现类是ApplicationServletEnvironment。
6.打印启动横幅:Banner
Banner printedBanner = printBanner(environment);
这行代码最终干了这么一件事,我们也可以自己定制他~
7.创建上下文:ConfigurableApplicationContext
protected ConfigurableApplicationContext createApplicationContext() {
// 根据type调用工厂类获取实例
return this.applicationContextFactory.create(this.webApplicationType);
}
ApplicationContextFactory DEFAULT = (webApplicationType) -> {
try {
switch (webApplicationType) {
case SERVLET:
// 带注解配置的servlet web服务器应用上下文
return new AnnotationConfigServletWebServerApplicationContext();
case REACTIVE:
// 带注解配置的reactive web服务器应用上下文
return new AnnotationConfigReactiveWebServerApplicationContext();
default:
// 带注解的应用上下文
return new AnnotationConfigApplicationContext();
}
}
catch (Exception ex) {
throw new IllegalStateException("Unable create a default ApplicationContext instance, "
+ "you may need a custom ApplicationContextFactory", ex);
}
};
因为项目加了spring-web包,所以最后返回的是AnnotationConfigServletWebServerApplicationContext对象
8.准备上下文:AnnotationConfigServletWebServerApplicationContext
在方法prepareContext中会对应用上下文进行赋值,所做的工作如下:
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
// 后置处理器注册(转换器、bean名称生成器、资源加载器)
postProcessApplicationContext(context);
// 获取ApplicationContextInitializer并初始化它们
applyInitializers(context);
// 广播ApplicationContextInitializedEvent事件
listeners.contextPrepared(context);
// 关闭启动上下文
bootstrapContext.close(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// 将ApplicationArguments和Banner注册到ioc容器工厂
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// 如果是项目是懒加载,就添加一个懒加载的后置处理器
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
// 加载BeanDefinitionLoader
load(context, sources.toArray(new Object[0]));
// 广播ApplicationPreparedEvent事件
listeners.contextLoaded(context);
}
9.刷新上下文:AnnotationConfigServletWebServerApplicationContext
private void refreshContext(ConfigurableApplicationContext context) {
if (this.registerShutdownHook) {
// 注册应用关闭时的钩子函数,用来清理资源
shutdownHook.registerApplicationContext(context);
}
// 调用父类抽象方法
refresh(context);
}
此处refresh()方法调用的是抽象类AbstractApplicationContext的refresh方法,接下来将涉及到spring的IOC容器的初始化和依赖注入:
public void refresh() throws BeansException, IllegalStateException {
// 加锁处理容器刷新
synchronized (this.startupShutdownMonitor) {
// 记录步骤
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
// 刷新前的准备工作
prepareRefresh();
// 获取一个可重复刷新的Bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 刷新前对Bean工厂的准备工作
prepareBeanFactory(beanFactory);
try {
// bean工厂创建后的后置处理(用于子类拓展)
postProcessBeanFactory(beanFactory);
// 记录步骤beanPostProcess
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// 执行上下文工厂中注册的后置处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 注册bean创建的拦截器。
registerBeanPostProcessors(beanFactory);
// 记录步骤关闭
beanPostProcess.end();
// 初始化上下文的信息国际化
initMessageSource();
// 初始化上下文的事件广播
initApplicationEventMulticaster();
// 初始化子类的bean
onRefresh();
// 注册监听器
registerListeners();
// 初始化剩余的单例bean
finishBeanFactoryInitialization(beanFactory);
// 刷新完成时处理(广播世界等)
finishRefresh();
}
catch (BeansException ex) {
...
}
finally {
// 重置缓存
resetCommonCaches();
// 记录步骤关闭
contextRefresh.end();
}
}
}
10.刷新后的后置处理
afterRefresh(context, applicationArguments)
这是个空方法,留给开发者拓展使用