Spring Boot启动
public class SpringApplication(){
// ......省略
/**
* Static helper that can be used to run a {@link SpringApplication} from the
* specified sources using default settings and user supplied arguments.
* @param primarySources the primary sources to load
* @param args the application arguments (usually passed from a Java main method)
* @return the running {@link ApplicationContext}
*/
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
}
SpringBoot启动实际上是分为两个部分,创建Application对象,启动该对象:
创建Application对象
/**
* Create a new {@link SpringApplication} instance. The application context will load
* beans from the specified primary sources (see {@link SpringApplication class-level}
* documentation for details. The instance can be customized before calling
* {@link #run(String...)}.
* @param resourceLoader the resource loader to use
* @param primarySources the primary bean sources
* @see #run(Class, String[])
* @see #setSources(Set)
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
//赋值空
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// 1.确定运行主类 SpringBootCodeApplication,获取对应资源,
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 2.设置Web容器类型 Servlet,Reactive,None
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 3.加载SpringApplication启动时需要的初始化器 从spring.factories(Spring-boot-start,spring-boot-auto-aware)中加载全限定名的类
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 4.加载SpringApplication启动所需监听器,11个
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 5.从跟踪栈中获取当前运行主类并交给被创建出的Application对象
this.mainApplicationClass = deduceMainApplicationClass();
}
从spring.factories中加载指定的类,实际上是通过FactoriesLoader通过指定类名来加载该类下所需所有子类,子类可能会有重复的会自动合并其中到HashSet中,并加载到Application的Cache中。
//从指定的spring.factories加载指定类下的子类,包括全限定类名和调用其构造方法初始化实体保存在Application的initializers 和 listeners中
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));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
//设置缓存
/**
* Sets the {@link ApplicationContextInitializer} that will be applied to the Spring
* {@link ApplicationContext}.
* @param initializers the initializers to set
*/
public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) {
this.initializers = new ArrayList<>(initializers);
}
运行Application.run方法
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
// 1.初始化计时器,计算程序运行时间
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 2.初始化Application上下文Context
ConfigurableApplicationContext context = null;
// 3.初始化错误报告器,记录启动报错集合
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// 4.根据是否有输入输出设备来设置可视化相关东西, awt
configureHeadlessProperty();
// 5.加载并创建SpringApplicationListner 运行监听器,实际上是将之前加载的监听器都加入到该监听器
// 中,方便后面启动时监听器群发监听事件
SpringApplicationRunListeners listeners = getRunListeners(args);
// 6.启动监听器,筛选出监听
listeners.starting();
try {
//初始化Application中参数封装成对象,实际上是将命令行参数封装成Arguments对象
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//准备生成Application环境对象,其中包括各个参数的Source,ServletContext,ServletProperties,SystemContext,SystemProperties
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
// 根据不同的容器(Servlet,Reactive,None)创建应用上下文 ApplicationContext
context = createApplicationContext();
// 创建异常报告器,用于处理和报告异常
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//填充容器上下文Context
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//刷新上下文 非常重要!!!!!
refreshContext(context);
// 刷新后操作,没有具体实现可以支持重写
afterRefresh(context, applicationArguments);
//停止计时器
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
getRunListeners(args);
getRunListeners实际上是加载spring.factories中的(org.springframework.boot.context.event.EventPublishingRunListener)类,在该类的构造方法中会将当前的application和所有监听器加载到当前的对象中,方便实用。
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
listeners.starting();
PublishingRunListener的starting方法会向当前所有监听器中可以监听ApplicationStartingEvent 事件的监听器发送事件,实际上只有两个监听器有对StartingEvent实际的操作。
//
@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 {
//执行每个监听器中的onApplicationEvent方法
// 实际上只有两个监听器会进来
// LoggingApplicationListner:日志相关
// BackgroundPreinitializer: 执行物种初始化器,其中一个conver类型转换 performPreinitialization();
invokeListener(listener, event);
}
}
}
// Add listeners by bean name, potentially overlapping with programmatically
// registered listeners above - but here potentially with additional metadata.
if (!listenerBeans.isEmpty()) {
ConfigurableBeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : listenerBeans) {
try {
if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
ApplicationListener<?> listener =
beanFactory.getBean(listenerBeanName, ApplicationListener.class);
// TODO 用event来判断当前监听器是否监听该时间
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
if (beanFactory.isSingleton(listenerBeanName)) {
retriever.applicationListeners.add(listener);
}
else {
retriever.applicationListenerBeans.add(listenerBeanName);
}
}
allListeners.add(listener);
}
}
else {
// Remove non-matching listeners that originally came from
// ApplicationListenerDetector, possibly ruled out by additional
// BeanDefinition metadata (e.g. factory method generics) above.
Object listener = beanFactory.getSingleton(listenerBeanName);
if (retriever != null) {
retriever.applicationListeners.remove(listener);
}
allListeners.remove(listener);
}
}
catch (NoSuchBeanDefinitionException ex) {
// Singleton listener instance (without backing bean definition) disappeared -
// probably in the middle of the destruction phase
}
}
}
AnnotationAwareOrderComparator.sort(allListeners);
if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {
retriever.applicationListeners.clear();
retriever.applicationListeners.addAll(allListeners);
}
return allListeners;
}
prepareEnvironment(listeners, applicationArguments);
准备并配置Application的环境对象
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
// 初始化环境对象
ConfigurableEnvironment environment = getOrCreateEnvironment();
//配置环境对象
configureEnvironment(environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
prepareContext();
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
// 将准备好的环境相关信息(Servlet和System的Porperties和Context,和命令行参数等等)
context.setEnvironment(environment);
// 应用上下文处理,主要是BackGroundLisner添加各类的转换器(Conver)
postProcessApplicationContext(context);
// 为上下文应用初始所有初始化器进行初始化,主要是将七个初始化器加载到SpringApplicationContext中
applyInitializers(context);
// 出发订阅了ApplicationContextInitializedEvent了的监听器
listeners.contextPrepared(context);
// 记录启动日志
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// 注册启动参数bean,将容器指定的参数封装成bean,注入容器
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// 是否启用懒加载Bean处理器
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// 加载所有资源Servlet/System 的properties和命令行参数等
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
// 注册Bean,
load(context, sources.toArray(new Object[0]));
//触发订阅了ApplicationPreparedEvent该事件的监听器
listeners.contextLoaded(context);
}
refreshContext(context);
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 刷新上下文环境,初始化上下文环境,对系统的环境变量或者系统属性进行准备和校验
prepareRefresh();
// 初始化beanfactory,解析xml,相当于之前的xmlBeanfactory操作
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 为上下文准备beanfactory,对beanFactory的各种功能进行填充,如@autowired,设置spel表达式解析器,设置编辑注册器,添加applicationContextAwareprocessor处理器等等
prepareBeanFactory(beanFactory);
try {
// 提供子类覆盖的额外处理,即子类处理自定义的beanfactorypostProcess
postProcessBeanFactory(beanFactory);
// 激活各种beanfactory处理器 重点!!!!
invokeBeanFactoryPostProcessors(beanFactory);
// 注册拦截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();
}
}
}
SpringBoot 自动装载
总结:
1、springboot启动会加载大量的自动配置类
2、查看需要的功能有没有在springboot默认写好的自动配置类中华
3、查看这个自动配置类到底配置了哪些组件
4、给容器中自动配置类添加组件的时候,会从properties类中获取属性
@Conditional:自动配置类在一定条件下才能生效
@Conditional扩展注解 | 作用 |
---|---|
@ConditionalOnJava | 系统的java版本是否符合要求 |
@ConditionalOnBean | 容器中存在指定Bean |
@ConditionalOnMissingBean | 容器中不存在指定Bean |
@ConditionalOnExpression | 满足SpEL表达式 |
@ConditionalOnClass | 系统中有指定的类 |
@ConditionalOnMissingClass | 系统中没有指定的类 |
@ConditionalOnSingleCandidate | 容器中只有一个指定的Bean,或者是首选Bean |
@ConditionalOnProperty | 系统中指定的属性是否有指定的值 |
@ConditionalOnResource | 类路径下是否存在指定资源文件 |
@ConditionOnWebApplication | 当前是web环境 |
@ConditionalOnNotWebApplication | 当前不是web环境 |
@ConditionalOnJndi | JNDI存在指定项 |
SpringBoot怎么自定义Starts
1.创建自定义Starts的Java文件
2.让该类被@Configuration修饰并使用@Condition来表示该配置什么条件下会被加载
3.给该Start增加所需要的组件(如果有需要的话)
4.在resource下创建META-INFO文件夹并出创建spring.factories文件
5.在该文件中增对EnableAutoConfiguration这个类增加自定义的子类(该类是SpringBoot的自动加载类,会在SpringBoot启动的时候把该类下配置的子类都加在进来)