启动类
@SpringBootApplication
public class SpringmvcApplication {
public static void main(String[] args) {
SpringApplication.run(SpringmvcApplication.class, args);
}
}
@SpringBootApplication
首先看@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 {
}
很明显,@SpringBootApplication注解由三个注解组合而成,分别是:
- @ComponentScan
- @EnableAutoConfiguration
- @SpringBootConfiguration
2.1 @ComponentScan
@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 {
}
这个注解的作用是告诉Spring扫描哪个包下面类,加载符合条件的组件(比如贴有@Component和@Repository等的类)或者bean的定义。
所以有一个basePackages的属性,如果默认不写,则从声明@ComponentScan所在类的package进行扫描。
所以启动类最好定义在Root package下,因为一般我们在使用@SpringBootApplication时,都不指定basePackages的
2.2 @EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
这是一个复合注解,看起来很多注解,实际上关键在@Import注解,它会加载
AutoConfigurationImportSelector类,然后就会触发这个类的selectImports()方法。根据返回的String数组(配置类的Class的名称)加载配置类
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
//返回的String[]数组,是配置类Class的类名
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
//返回配置类的类名
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
我们一直点下去,就可以找到最后的幕后英雄,就是SpringFactoriesLoader类,通过loadSpringFactories()方法加载META-INF/spring.factories中的配置类。
这里使用了spring.factories文件的方式加载配置类,提供了很好的扩展性。
所以@EnableAutoConfiguration注解的作用其实就是开启自动配置,自动配置主要则依靠这种加载方式来实现
2.3 @SpringBootConfiguration
@SpringBootConfiguration继承自@Configuration,二者功能也一致,标注当前类是配置类, 并会将当前类内声明的一个或多个以@Bean注解标记的方法的实例纳入到spring容器中,并且实例名就是方法名。
2.4 小结
SpringApplication类
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
//断言primarySources不能为null,如果为null,抛出异常提示
Assert.notNull(primarySources, "PrimarySources must not be null");
//启动类传入的Class
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//判断当前项目类型,有三种:NONE、SERVLET、REACTIVE
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//设置ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//设置监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//判断主类,初始化入口类
创建了SpringApplication实例之后,就完成了SpringApplication类的初始化工作,这个实例里包括监听器、初始化器,项目应用类型,启动类集合,类加载器。如图所示

得到SpringApplication实例后,接下来就调用实例方法run()。继续看
创建了SpringApplication实例之后,就完成了SpringApplication类的初始化工作,这个实例里包括监听器、初始化器,项目应用类型,启动类集合,类加载器。如图所示。

得到SpringApplication实例后,接下来就调用实例方法run()。继续看。
public ConfigurableApplicationContext run(String... args) { //创建计时器 StopWatch stopWatch = new StopWatch(); //开始计时 stopWatch.start(); //定义上下文对象 ConfigurableApplicationContext context = null; Collection exceptionReporters = new ArrayList<>(); //Headless模式设置 configureHeadlessProperty(); //加载SpringApplicationRunListeners监听器 SpringApplicationRunListeners listeners = getRunListeners(args); //发送ApplicationStartingEvent事件 listeners.starting(); try { //封装ApplicationArguments对象 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); //配置环境模块 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); //根据环境信息配置要忽略的bean信息 configureIgnoreBeanInfo(environment); //打印Banner标志 Banner printedBanner = printBanner(environment); //创建ApplicationContext应用上下文 context = createApplicationContext(); //加载SpringBootExceptionReporter exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); //ApplicationContext基本属性配置 prepareContext(context, environment, listeners, applicationArguments, printedBanner); //刷新上下文 refreshContext(context); //刷新后的操作,由子类去扩展 afterRefresh(context, applicationArguments); //计时结束 stopWatch.stop(); //打印日志 if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } //发送ApplicationStartedEvent事件,标志spring容器已经刷新,此时所有的bean实例都已经加载完毕 listeners.started(context); //查找容器中注册有CommandLineRunner或者ApplicationRunner的bean,遍历并执行run方法 callRunners(context, applicationArguments); } catch (Throwable ex) { //发送ApplicationFailedEvent事件,标志SpringBoot启动失败 handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); }
try { //发送ApplicationReadyEvent事件,标志SpringApplication已经正在运行,即已经成功启动,可以接收服务请求。 listeners.running(context); } catch (Throwable ex) { //报告异常,但是不发送任何事件 handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }
this.mainApplicationClass = deduceMainApplicationClass();
}
以上就是创建SpringApplication实例做的事情,下面用张图来表示一下
创建了SpringApplication实例之后,就完成了SpringApplication类的初始化工作,这个实例里包括监听器、初始化器,项目应用类型,启动类集合,类加载器。如图所示
得到SpringApplication实例后,接下来就调用实例方法run()。继续看。
public ConfigurableApplicationContext run(String... args) {
//创建计时器
StopWatch stopWatch = new StopWatch();
//开始计时
stopWatch.start();
//定义上下文对象
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
//Headless模式设置
configureHeadlessProperty();
//加载SpringApplicationRunListeners监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
//发送ApplicationStartingEvent事件
listeners.starting();
try {
//封装ApplicationArguments对象
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//配置环境模块
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
//根据环境信息配置要忽略的bean信息
configureIgnoreBeanInfo(environment);
//打印Banner标志
Banner printedBanner = printBanner(environment);
//创建ApplicationContext应用上下文
context = createApplicationContext();
//加载SpringBootExceptionReporter
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//ApplicationContext基本属性配置
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//刷新上下文
refreshContext(context);
//刷新后的操作,由子类去扩展
afterRefresh(context, applicationArguments);
//计时结束
stopWatch.stop();
//打印日志
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
//发送ApplicationStartedEvent事件,标志spring容器已经刷新,此时所有的bean实例都已经加载完毕
listeners.started(context);
//查找容器中注册有CommandLineRunner或者ApplicationRunner的bean,遍历并执行run方法
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
//发送ApplicationFailedEvent事件,标志SpringBoot启动失败
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
//发送ApplicationReadyEvent事件,标志SpringApplication已经正在运行,即已经成功启动,可以接收服务请求。
listeners.running(context);
}
catch (Throwable ex) {
//报告异常,但是不发送任何事件
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}