SpringBoot启动结构图
springboot启动分为构造器部分和run部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 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 = WebApplicationType.deduceFromClasspath(); this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories(); setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }
|
运行SpringApplication
创建上下文—启动监听器—创建IOC容器—准备环境—刷新IOC容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); DefaultBootstrapContext bootstrapContext = createBootstrapContext(); ConfigurableApplicationContext context = null; configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(bootstrapContext, this.mainApplicationClass); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); context.setApplicationStartup(this.applicationStartup); prepareContext(bootstrapContext, 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, listeners); throw new IllegalStateException(ex); } try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, null); throw new IllegalStateException(ex); } return context; }
|
springboot如何实现自动装配
归功于springboot强大的注解功能,也是springboot的一大特点
举例:在springboot主运行程序中,下面是常见的springboot启动类
1 2 3 4 5 6
| @SpringBootApplication public class SpringbootSrcApplication { public static void main(String[] args) { SpringApplication.run(SpringbootSrcApplication.class, args); } }
|
spring会在启动的时候new自己—>new SpringApplication(primarySources).run(args)这时候就会初始化,并加载扫描到所有的组件进入缓存

真正发挥作用的是@Import(),它导什么,容器实例化什么
先来从@SpringBootApplication这个注解说起

主要的注解为@SpringBootConfiguration+@ComponentScan+@EnableAutoConfiguration
前两个没什么好说的,@SpringBootConfiguration就是封装了@Configuration注解,表示他是一个配置类

@ComponentScan:扫描注解,表示哪些会被spring扫描到
那么重要的就是@EnableAutoConfiguration,见名知意拥有自动配置的能力,点进去看下

主要注解为@AutoConfigurationPackage+@Import,而@AutoConfigurationPackage其中也是@Import,所以起到主要作用的就是@Import这个注解了
@Import:给容器中导入一个组件,前提是必须作用于spring的组件下,可以自动调用组件的无参构造器创建对象
1 2 3 4 5 6 7 8 9 10
| @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Import {
Class<?>[] value(); }
|
由上图可知import导入了AutoConfigurationImportSelector.class这个组件,那么程序中是什么时候导入的?
spring容器启动会刷新IOC容器(refreshContext(context))执行invokeBeanFactoryPostProcessors方法,最终调用到getImports()这个方法,这个方法会将标有@Import的组件进行实例化
1 2 3 4 5 6 7 8
| public Iterable<Group.Entry> getImports() { for (DeferredImportSelectorHolder deferredImport : this.deferredImports) { this.group.process(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getImportSelector()); } return this.group.selectImports(); }
|
上述方法会执行AutoConfigurationImportSelector类的process方法
调用核心方法SpringFactoriesLoader.loadFactoryNames导入一系列组件

拓展部分,怎么导入的?
接上段程序,调用关键语句
1 2
| List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
|
其中getSpringFactoriesLoaderFactoryClass()返回的正是@EnableAutoConfiguration这个注解
1 2 3
| protected Class<?> getSpringFactoriesLoaderFactoryClass() { return EnableAutoConfiguration.class; }
|
点进去loadFactoryNames
1 2 3 4 5 6 7 8 9 10 11 12 13
| public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) { ClassLoader classLoaderToUse = classLoader; if (classLoaderToUse == null) { classLoaderToUse = SpringFactoriesLoader.class.getClassLoader(); } String factoryTypeName = factoryType.getName(); return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList()); }
|
怎么实例化的
spring在刷新IOC的最后一步会调用finishBeanFactoryInitialization(beanFactory)方法,来实例化剩余的非lazy的单例,在调用过程中beanFactory.preInstantiateSingletons(),该方法会遍历所有的bean
按需配置
注解有如下几项:
@ConditionalOnBean:当容器里有指定的bean的条件下
@ConditionalOnMissingBean:当容器里不存在指定bean的条件下
@ConditionalOnClass:当类路径下有指定类的条件下
@ConditionalOnMissingClass:当类路径下不存在指定类的条件下
@ConditionalOnProperty:指定的属性是否有指定的值,比如
@ConditionalOnProperties(prefix=”xxx.xxx”, value=”enable”, matchIfMissing=true),代表当xxx.xxx为enable时条件的布尔值为true,如果没有设置的情况下也为true