SpringBoot 启动过程
- SpringApplication的初始化模块,配置一些基本的环境变量、资源、构造器、监听器
- 实现了应用具体的启动方案,包括启动流程的监听模块、加载配置环境模块、及核心的创建上下文环境模块
- 自动化配置模块,该模块作为springboot自动配置核心
启动类上的注解:
@SpringBootApplication
- @EnableAutoConfiguration:根据应用所生命的依赖来对Spring框架进行自动配置
- @AutoConfigurationPackages:注册当前同级以及子级的包中的符合条件(如@Configuration)的bean的定义
- @Import(AutoConfigurationImportSelector.class)扫描各个组件jar META-INF目录下的spirng.factories文件,将下面的包名.类名中的工程类全部进行加载到IOC容器中
- @SpringBootConfiguration(内部@Configuration)等于在spring的xml配置文件(applicationContext.xml)中,装配所有bean事务,提供了一个spring的上下文环境
- @ComoonentScan:子健扫描,自动发现和装配bean。默认扫描启动类所在的包路径下文件,所以要把启动类放在根包路径。
@ImportResource(加载xml文件)
启动流程
1、创建了应用的监听器SpringApplicationRunListeners并开始监听
2、加载配置环境ConfigurableEnvironment,如果是web则会加载StandardEnvironment。
3、配置环境加入到监听器对象中
4、创建run方法的返回对象:ConfigurableApplicationContext(应用配置上下文)
5、prepareContext方法将listeners、environment、applicationArguments、banner等组件与上下文对象关联
6、refreshContext方法,即AbstractApplicationContext的refresh方法,完成后进行shutdown钩子的注册。并做了一些收尾工作返回了应用上下文对象。
自动化配置
-
AutoConfigurationImportSelector,通过@Import导入到Spring容器,提供了selectImports方法,将所有需要导入的组件以全类名的方式返回。
-
selectImports方法中有一个getCandidateConfigurations方法,调用了SpringFactoriesLoader.loadFactoryNames方法。
public String[] selectImports(AnnotationMetadata metadata) { if (!this.isEnabled(metadata)) { return NO_IMPORTS; } else { try { //获取 @EnableAutoConfigoration 标注类的元信息,也就是获取该注解 exclude、excludeName 属性值 AnnotationAttributes attributes = this.getAttributes(metadata); //获取META-INF/spring.factories文件下自动装配的类名集合 List<String> configurations = this.getCandidateConfigurations(metadata, attributes); //去除重复的自动装配组件,就是将List转为Set进行去重 configurations = this.removeDuplicates(configurations); //这部分就是根据上面获取的 exclude 及 excludeName 属性值,排除指定的类 Set<String> exclusions = this.getExclusions(metadata, attributes); //删除对应的例外配置 configurations.removeAll(exclusions); //排序,因为自动配置会有bean引用依赖,先按字母排序,再根据order排序,再根据ConfigurationBefore等排序 configurations = this.sort(configurations); //输出满足条件的配置项目 this.recordWithConditionEvaluationReport(configurations, exclusions); return (String[])configurations.toArray(new String[configurations.size()]); } catch (IOException var5) { throw new IllegalStateException(var5); } } }
-
-
SpringFacotiesLoader:工厂加载器,提供了loadFactoryNames方法,入参为factoryClass和classLoader,调用loadSpringFactories方法,会扫描所有jar包类路径下META-INF/spring.factories文件的内容,即根据@EnableAutoConfiguration的完整类名org.springframework.boot.autoconfigure.EnableAutoConfiguration作为查找的Key,获取对应的一组@Configuration类,包装成properties对象,获取到EnableAutoConfiguration的实现类的全限定名,反射实例化后添加到IOC容器中。
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); } private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { MultiValueMap<String, String> result = cache.get(classLoader); if (result != null) return result; try { Enumeration<URL> urls = (classLoader != null ? //META-INF/spring.factories classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); result = new LinkedMultiValueMap<>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); for (Map.Entry<?, ?> entry : properties.entrySet()) { List<String> factoryClassNames = Arrays.asList( StringUtils.commaDelimitedListToStringArray((String) entry.getValue())); result.addAll((String) entry.getKey(), factoryClassNames); } } cache.put(classLoader, result); return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } }
对每一个自动配置类进行自动配置功能,通过properties前缀来获取该配置类的配置项
在 Spring Boot 项目中,我们将大量的参数配置在 application.properties 或 application.yml 文件中,通过@ConfigurationProperties 注解,我们可以获取这些参数值