springcloud情操陶冶-springcloud context(二)

承接前文对bootstrapContext创建的引导,笔者了解到其主要入口类为BootstrapImportSelectorConfiguration。本文将基于此类进行简单的分析 BootstrapImportSelectorConfiguration 简单的配置类,看下源码 @Configuration @Import(BootstrapImportSelector.class) public class BootstrapImportSelectorConfiguration { } 嗯,引入了延迟加载类BootstrapImportSelector,那笔者就继续往下看下此会延迟加载哪些类,直接去观察其主方法 @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // Use names and ensure unique to protect against duplicates List names = new ArrayList<>(SpringFactoriesLoader .loadFactoryNames(BootstrapConfiguration.class, classLoader)); names.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray( environment.getProperty("spring.cloud.bootstrap.sources", "")))); List elements = new ArrayList<>(); for (String name : names) { try { elements.add(new OrderedAnnotatedElement(metadataReaderFactory, name)); } catch (IOException e) { continue; } } AnnotationAwareOrderComparator.sort(elements); String[] classNames = elements.stream() .map(e -> e.name) .toArray(String[]::new); return classNames; } 上述的代码很简单,其会去加载classpath路径下spring.factories文件中以org.springframework.cloud.bootstrap.BootstrapConfiguration作为Key的所有类; 同时springcloud也支持通过设置spring.cloud.bootstrap.sources属性来加载指定类 笔者就先以springcloud context板块内的spring.factories作为分析的源头 # Bootstrap components org.springframework.cloud.bootstrap.BootstrapConfiguration=\ org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration,\ org.springframework.cloud.bootstrap.encrypt.EncryptionBootstrapConfiguration,\ org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration,\ org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration 在分析上述的源码之前,笔者必须得清楚现在bootstrapContext加载的配置文件默认为bootstrap.properties抑或是bootstrap.yml。基于此我们再往下走,以免犯糊涂 PropertySourceBootstrapConfiguration 配置源的加载,此Configuration主要用于确定是否外部加载的配置属性复写Spring内含的环境变量。注意其是ApplicationContextInitializer接口的实现类,前文已经提到,bootstrapContext上的此接口的bean类都会被注册至子级的SpringApplication对象上。 直接看下主要的代码片段把 @Override public void initialize(ConfigurableApplicationContext applicationContext) { CompositePropertySource composite = new CompositePropertySource( BOOTSTRAP_PROPERTY_SOURCE_NAME); AnnotationAwareOrderComparator.sort(this.propertySourceLocators); boolean empty = true; // 此处为子级的环境变量对象 ConfigurableEnvironment environment = applicationContext.getEnvironment(); // 通过PropertySourceLocator接口去加载外部配置 for (PropertySourceLocator locator : this.propertySourceLocators) { PropertySource source = null; source = locator.locate(environment); if (source == null) { continue; } logger.info("Located property source: " + source); composite.addPropertySource(source); empty = false; } if (!empty) { MutablePropertySources propertySources = environment.getPropertySources(); String logConfig = environment.resolvePlaceholders("${logging.config:}"); LogFile logFile = LogFile.get(environment); if (propertySources.contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) { propertySources.remove(BOOTSTRAP_PROPERTY_SOURCE_NAME); } // 确定属性读取的先后顺序 insertPropertySources(propertySources, composite); // reinitialize log reinitializeLoggingSystem(environment, logConfig, logFile); setLogLevels(applicationContext, environment); // active profiles process handleIncludedProfiles(environment); } } 上述的代码就涉及两点,一个是通过PropertySourceLocator接口加载外部配置;一个是用于解析以spring.cloud.config为开头的PropertySourceBootstrapProperties属性,默认情况下,外部配置比内部变量有更高的优先级。具体的用户可自行分析 备注:PropertiesSourceBootstrapProperties中的属性变量可通过系统变量抑或是application.properties等文件配置 PropertyPlaceholderAutoConfiguration 和spring常见的解析文件一样的操作,具体就不分析了 @Configuration @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) public class PropertyPlaceholderAutoConfiguration { // 配置文件属性读取常用类 @Bean @ConditionalOnMissingBean(search = SearchStrategy.CURRENT) public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); } } ConfigurationPropertiesRebinderAutoConfiguration 通过命名便会发现其跟刷新属性的功能有关,先优先看下其类结构 @Configuration @ConditionalOnBean(ConfigurationPropertiesBindingPostProcessor.class) public class ConfigurationPropertiesRebinderAutoConfiguration implements ApplicationContextAware, SmartInitializingSingleton { } 上述代码表示其依据于当前类环境存在ConfigurationPropertiesBindingPostProcessorBean对象才会被应用,仔细查阅了下,发现只要有使用到@EnableConfigurationProperties注解即就会被注册。看来此配置跟ConfigurationProperties注解也有一定的关联性。 本文就罗列笔者比较关注的几个地方 1.ConfigurationPropertiesRebinder对象的创建 @Bean @ConditionalOnMissingBean(search = SearchStrategy.CURRENT) public ConfigurationPropertiesRebinder configurationPropertiesRebinder( ConfigurationPropertiesBeans beans) { ConfigurationPropertiesRebinder rebinder = new ConfigurationPropertiesRebinder( beans); return rebinder; } 此类读者可以自行翻阅代码,可以发现其暴露了JMX接口以及监听了springcloud context自定义的EnvironmentChangeEvent事件。看来其主要用来刷新ApplicationContext上的beans(含@ConfigurationProperties注解)对象集合 2.ConfigurationPropertiesBeans对象的创建 @Bean @ConditionalOnMissingBean(search = SearchStrategy.CURRENT) public ConfigurationPropertiesBeans configurationPropertiesBeans() { // ConfigurationBeanFactoryMetadata metaData = this.context.getBean( ConfigurationBeanFactoryMetadata.BEAN_NAME, ConfigurationBeanFactoryMetadata.class); ConfigurationPropertiesBeans beans = new ConfigurationPropertiesBeans(); beans.setBeanMetaDataStore(metaData); return beans; } 配合ConfigurationProperties注解的表演,其会缓存ApplicationContext上的所有含有ConfigurationProperties注解的bean。与第一点所提的ConfigurationPropertiesRebinder对象搭配使用 3.实例化结束后刷新父级ApplicationContext上的属性 @Override public void afterSingletonsInstantiated() { // refresh parent application context if (this.context.getParent() != null) { // TODO: make this optional? (E.g. when creating child contexts that prefer to // be isolated.) ConfigurationPropertiesRebinder rebinder = context .getBean(ConfigurationPropertiesRebinder.class); for (String name : context.getParent().getBeanDefinitionNames()) { rebinder.rebind(name); } } } EncryptionBootstrapConfiguration 与属性读取的加解密有关,跟JDK的keystore也有一定的关联,具体就不去解析了。读者可自行分析 其余关联类 比如springcloud config-client模块下的spring.factories # Bootstrap components org.springframework.cloud.bootstrap.BootstrapConfiguration=\ org.springframework.cloud.config.client.ConfigServiceBootstrapConfiguration,\ org.springframework.cloud.config.client.DiscoveryClientConfigServiceBootstrapConfiguration 和springcloud config-server模块下的spring.factories # Bootstrap components org.springframework.cloud.bootstrap.BootstrapConfiguration=\ org.springframework.cloud.config.server.bootstrap.ConfigServerBootstrapConfiguration,\ org.springframework.cloud.config.server.config.EncryptionAutoConfiguration 限于本篇幅过长,就不在此讨论server和client模块对bootstrapContext的作用。后文再作详细的讨论 小结 1.针对springcloud context模块下的以BootstrapConfiguration作为Key的自动配置类,除了PropertySourceBootstrapConfiguration自动类的应用范围在子级ApplicationContext,其它三个均有作用于父级ApplicationContext。 2.关于外部源文件的属性,默认情况下其有更高的优先级于本地系统以及环境变量。当然用户也可以通过修改spring.cloud.config.allowOverride/spring.cloud.config.overrideSystemProperties/spring.cloud.config.overrideNone属性来进行优先级更改,通过此,用户也可以复写PropertySourceLocator接口来获取外部源 package com.example.cloud.external.resource; import org.springframework.cloud.bootstrap.config.PropertySourceLocator; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.PropertySource; import java.util.HashMap; import java.util.Map; /** * @author nanco * ------------- * cloud-demo * ------------- * @create 2019/1/15 19:40 * @descrption **/ @Configuration public class ExternalPropertySourceLocator implements PropertySourceLocator { private static final String EXTERNAL_KEY = "external"; @Override public PropertySource locate(Environment environment) { Map externalMap = new HashMap<>(); externalMap.put("username", "nanco"); externalMap.put("password", "nanco123"); externalMap.put("mail", "nancoasky@gmail.com"); return new MapPropertySource(EXTERNAL_KEY, externalMap); } } 作者:南柯问天 出处:http://www.cnblogs.com/question-sky/ 本文版权归本人和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律https://www.cnblogs.com/question-sky/p/10273939.html
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信