其实现也是通过类似@Import的方式注入AutoConfigurationImportSelector类,并借助该类将所有符合条件的Configuration注解修饰的配置类加载到Spring Boot容器中。从classpath中搜索所有的META-INF/spring.factories配置文件,将其中org.springframework.boot.autoconfigure.EnableAutoConfiguration对应配置项通过反射的形式实例化为标注了@Configuration和javaconfig形式的IOC容器配置类,然后汇总为一个并加载到ioc容器中。
@ComponentScan
这个注解就不需要多介绍了吧,其作用自动扫描加载符合条件的bean。
SpringApplication从项目的入口第一个碰到的就是SpringApplication类。
@SpringBootApplication public class TutorialApplication { public static void main(String[] args) { SpringApplication.run(TutorialApplication.class, args); } }进入该类的静态方法run,可以看到其在构造SpringApplication对象
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return new SpringApplication(primarySources).run(args); }进入SpringApplication构造方法,可以看到
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); this.webApplicationType = deduceWebApplicationType(); setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }主要做了如下几件事:
加载Source,这里只有只有Application
推断WebApplicationType,该枚举有三种类型NONE、SERVLET、REACTIVE。
设置初始化器变量setInitializers,初始化后得到6个初始化变量,这些类在上面提到的spring.factories中可以找到
设置监听器,与上面setInitializers实现类似,最终得到如下10个listeners
最后推断带有main函数的所在类,即入口类,这里就是TutorialApplication
private Class<?> deduceMainApplicationClass() { try { StackTraceElement[] stackTrace = new RuntimeException().getStackTrace(); for (StackTraceElement stackTraceElement : stackTrace) { if ("main".equals(stackTraceElement.getMethodName())) { return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException ex) { // Swallow and continue } return null; } run方法看完SpringApplication是如何初始化后,我们来看下这个后面的run方法具体做了哪些事。
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, 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; }StopWatch,这是一个spring-core中的工具类,用来给程序运行计时(对于经常遇到需要计算某方法或接口耗时的场景,这个比System.currentTimeMillis好用)