1.说到启动配置原理我们无非就是去查看源代码。
首先我们从SpringBoot的启动类来入手我们在SpringBoot的类上打上断点来分析一下启动过程
然后我们使用F7(step into)查看我们发现,是先创建了SpringApplication对象再运行的Run方法
1.1. 创建SpringApplication对象
根据源代码我们可以得出以下结论
/**
* 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 要使用的资源加载器
* @param primarySources 主要配置类
* @see #run(Class, String[])
* @see #setSources(Set)
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
//将资源加载器保存下来
this.resourceLoader = resourceLoader;
//判断主配置类是不是为空,如果是则抛出IllegalArgumentException异常
Assert.notNull(primarySources, "PrimarySources must not be null");
//将住配置类给保存下来也就是一开始的启动类
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//判断web应用的类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//从类路径下找到META‐INF/spring.factories配置的所有ApplicationContextInitializer;然后保存起来
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//从类路径下找到ETA‐INF/spring.factories配置的所有ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//从多个配置类中找到有main方法的主配置类
this.mainApplicationClass = deduceMainApplicationClass();
}
保存的一些参数
1.2运行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) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
//创建一个ioc容器
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//获取SpringApplicationRunListeners;从类路径下META‐INF/spring.factories
SpringApplicationRunListeners listeners = getRunListeners(args);
//回调所有的获取SpringApplicationRunListener.starting()
listeners.starting();
try {
//封装命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
//创建环境完成后回调SpringApplicationRunListener.environmentPrepared();表示环境准备完成
configureIgnoreBeanInfo(environment);
//打印Banner
Banner printedBanner = printBanner(environment);
//创建ApplicationContext;决定创建的ioc的类型
context = createApplicationContext();
//异常
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[]{ConfigurableApplicationContext.class}, context);
//准备上下文环境;将environment保存到ioc中;而且applyInitializers();
//applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法
//回调所有的SpringApplicationRunListener的contextPrepared();
//prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded();
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//刷新容器,给context注册一个ShutdownHook
refreshContext(context);
//刷新后干嘛
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
//所有的SpringApplicationRunListener调用started方法
listeners.started(context);
//从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调
//ApplicationRunner先回调,CommandLineRunner再回掉
callRunners(context, applicationArguments);
} catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
//所有的SpringApplicationRunListener调用running方法
listeners.running(context);
} catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
//整个SpringBoot应用启动完成以后返回启动的ioc容器
return context;
}
这里面讲了很多源码里的方法,大家可以详细查看
2.事件监听机制
配置在META-INF/spring.factories
ApplicationContextInitializer
package com.ywj.springboot7.listener;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
/**
* @ClassName HelloApplicationContextInitializer
* @Author ywj
* @Describe
* @Date 2019/3/4 0004 3:23
*/
public class HelloApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
System.out.println("ApplicationContextInitializer...initialize..."+configurableApplicationContext);
}
}
SpringApplicationRunListener
package com.ywj.springboot7.listener;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
public class HelloSpringApplicationRunListener implements SpringApplicationRunListener {
//必须有的构造器
public HelloSpringApplicationRunListener(SpringApplication application, String[] args){
}
@Override
public void starting() {
System.out.println("SpringApplicationRunListener...starting...");
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
Object o = environment.getSystemProperties().get("os.name");
System.out.println("SpringApplicationRunListener...environmentPrepared.."+o);
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
System.out.println("SpringApplicationRunListener...contextPrepared...");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
System.out.println("SpringApplicationRunListener...contextLoaded...");
}
@Override
public void started(ConfigurableApplicationContext context) {
System.out.println("ConfigurableApplicationContext...started...");
}
@Override
public void running(ConfigurableApplicationContext context) {
System.out.println("ConfigurableApplicationContext...running...");
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
}
}
配置(META-INF/spring.factories)
只需要放在ioc容器中
ApplicationRunner
package com.ywj.springboot7.listener;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
/**
* @ClassName HelloApplicationRunner
* @Author ywj
* @Describe
* @Date 2019/3/4 0004 3:29
*/
@Component
public class HelloApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("ApplicationRunner...run....");
}
}
CommandLineRunner
package com.ywj.springboot7.listener;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* @ClassName HelloCommandLineRunner
* @Author ywj
* @Describe
* @Date 2019/3/4 0004 3:31
*/
@Component
public class HelloCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("CommandLineRunner...run..."+ Arrays.asList(args));
}
}