项目立项->开发->测试->维护->上线->维护,这几个过程中分为不同的环境。不同的环境不同业务有着不同的逻辑。 spring完美支持启动的时候加载不同的配置文件。我们通过指定不同的spring.profiles.active即可实现加载不同的配置文件。 不管怎么样默认会加载如下几个配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class ConfigFileApplicationListener implements EnvironmentPostProcessor , SmartApplicationListener , Ordered { ... private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/*/,file:./config/" ; private static final String DEFAULT_NAMES = "application" ; ... } public class PropertiesPropertySourceLoader implements PropertySourceLoader { ... @Override public String[] getFileExtensions() { return new String[]{"properties" , "xml" }; } ... } public class YamlPropertySourceLoader implements PropertySourceLoader { @Override public String[] getFileExtensions() { return new String[]{"yml" , "yaml" }; } }
5个位置,一个名称,4个后缀,总共有多少种组合?(还没有profile情况下😁)
加载流程 springBoot容器启动流程
springListener spring factories 配置了容器启动的监听类
1 2 3 4 5 org.springframework.context.ApplicationListener =\ ... org.springframework.boot.context.config.ConfigFileApplicationListener,\ ...
此监听类又独自搞了一套EnvironmentPostProcessor,同样也是用的spring spi机制来处理
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 public class ConfigFileApplicationListener implements EnvironmentPostProcessor , SmartApplicationListener , Ordered { public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 10 ; ... public void onApplicationEvent (ApplicationEvent event) { if (event instanceof ApplicationEnvironmentPreparedEvent) { onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event); } if (event instanceof ApplicationPreparedEvent) { onApplicationPreparedEvent(event); } } private void onApplicationEnvironmentPreparedEvent (ApplicationEnvironmentPreparedEvent event) { List<EnvironmentPostProcessor> postProcessors = SpringFactoriesLoader.loadFactories(EnvironmentPostProcessor.class, getClass().getClassLoader()); postProcessors.add(this ); AnnotationAwareOrderComparator.sort(postProcessors); for (EnvironmentPostProcessor postProcessor : postProcessors) { postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication()); } } public void postProcessEnvironment (ConfigurableEnvironment environment, SpringApplication application) { RandomValuePropertySource.addToEnvironment(environment); new Loader(environment, application.getResourceLoader()).load(); } ... }
真正加载的逻辑 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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 private class Loader { private final ConfigurableEnvironment environment; private final PropertySourcesPlaceholdersResolver placeholdersResolver; private final ResourceLoader resourceLoader; private final List<PropertySourceLoader> propertySourceLoaders; private Deque<Profile> profiles; private List<Profile> processedProfiles; private boolean activatedProfiles; private Map<Profile, MutablePropertySources> loaded; private Map<DocumentsCacheKey, List<Document>> loadDocumentsCache = new HashMap<>(); Loader(ConfigurableEnvironment environment, ResourceLoader resourceLoader) { this .environment = environment; this .placeholdersResolver = new PropertySourcesPlaceholdersResolver(this .environment); this .resourceLoader = (resourceLoader != null ) ? resourceLoader : new DefaultResourceLoader(null ); this .propertySourceLoaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class, getClass().getClassLoader()); } void load () { FilteredPropertySource.apply(this .environment, DEFAULT_PROPERTIES, LOAD_FILTERED_PROPERTY, (defaultProperties) -> { this .profiles = new LinkedList<>(); this .processedProfiles = new LinkedList<>(); this .activatedProfiles = false ; this .loaded = new LinkedHashMap<>(); initializeProfiles(); while (!this .profiles.isEmpty()) { Profile profile = this .profiles.poll(); if (isDefaultProfile(profile)) { addProfileToEnvironment(profile.getName()); } load(profile, this ::getPositiveProfileFilter, addToLoaded(MutablePropertySources::addLast, false )); this .processedProfiles.add(profile); } load(null , this ::getNegativeProfileFilter, addToLoaded(MutablePropertySources::addFirst, true )); addLoadedPropertySources(); applyActiveProfiles(defaultProperties); }); } }
至此代码分析完毕,如果想看更细节的东西,请移步至org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#load()
总结 通过监听springEnvironment事件,然后用spring SPI找出所有的EnvironmentPostProcessor Load类为加载配置文件的类。它的逻辑主要分为 1.初始化profile(包含null,以及未指定命令行参数的active时用defaultProfile) 2.循环profile加载(5个位置、1个名称、4个后缀)的文件 3.把加载的资源配置到spring的environment里面 4.setActiveProfiles