springcloud情操陶冶-bootstrapContext(二)
承接前文监听器对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<String> names = new ArrayList<>(SpringFactoriesLoader
.loadFactoryNames(BootstrapConfiguration.class, classLoader));
names.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(
environment.getProperty("spring.cloud.bootstrap.sources", ""))));
List<OrderedAnnotatedElement> 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,其属性已经被加入至相应的Environment对象中。基于此我们再往下走,以免犯糊涂
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中的属性变量可通过PropertySourceLocator接口配置
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也有一定的关联,具体就不去解析了。读者可自行分析
Bean加载问题
此处本文插入这个Bean的加载问题,因为笔者发现SpringApplication会被调用两次,那么ApplicationContext实例也会被创建两次。那么基于@Configuration修饰过的自定义的Bean是不是也会被加载两次呢??
经过在cloud环境下编写了一个简单的Bean
package com.example.clouddemo;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
/**
* @author nanco
* -------------
* -------------
* @create 19/8/20
*/
@Configuration
public class TestApplication implements ApplicationContextAware {
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("application parent context id: " + applicationContext.getParent().getId());
System.out.println("application context id: " + applicationContext.getId());
}
}
且在application.properties文件中指定spring.application.name=springChild以及bootstrap.properties文件中也指定spring.application.name=springBootstrap
运行main方法之后打印的关键信息如下
application parent context id: bootstrap
application context id: springBootstrap-1
经过在org.springframework.boot.context.ContextIdApplicationContextInitializer类上进行断点调试发现只有用户级ApplicationContext被创建的过程中会实例化用户自定义Bean。也就是说bootstrapContext并不会去实例化用户自定义的Bean,这样就很安全。
那么为何如此呢?其实很简单,因为bootstrapContext指定的source类只有BootstrapImportSelectorConfiguration,并没有用户编写的启动类,也就无法影响用户级别Context的Bean加载实例化了~~~并且该类上无@EnableAutoConfiguration注解,表明其也不会去处理spring.factories文件中@EnableAutoConfiguration注解key对应的配置集合。
小结
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<String, Object> externalMap = new HashMap<>();
// user custom property
externalMap.put("username", "nanco");
externalMap.put("password", "nanco123");
externalMap.put("mail", "nancoasky@gmail.com");
// application property
externalMap.put("spring.cloud.config.allowOverride", true);
externalMap.put("spring.cloud.config.overrideSystemProperties", false); //system拥有更高的优先级
externalMap.put("spring.cloud.config.overrideNone", false);
return new MapPropertySource(EXTERNAL_KEY, externalMap);
}
}
最后将上述的类放置在META-INF/spring.factories文件中便可以生效了
# Bootstrap components
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.example.cloud.external.resource.ExternalPropertySourceLocator
3.关于针对@ConfigurationProperties
注解的Beans对象的刷新操作,本文只讲解了JMX方式去调用,如果与第三方插件结合,应该会有更多的形式。
4.针对监听器环节的分析到本章暂时告一段落,下一篇便分析cloud-context板块spring.factories文件中以org.springframework.boot.autoconfigure.EnableAutoConfiguration作为Key的类集合。
熟悉的气息再次降临,迫不及待ing....
springcloud情操陶冶-bootstrapContext(二)的更多相关文章
- springcloud情操陶冶-bootstrapContext(一)
基于前文对springcloud的引导,本文则从源码角度查阅下cloud的context板块的运行逻辑 前言 springcloud是基于springboot开发的,所以读者在阅读此文前最好已经了解了 ...
- springcloud情操陶冶-bootstrapContext(三)
本文则将重点阐述context板块的自动配置类,观察其相关的特性并作相应的总结 自动配置类 直接查看cloudcontext板块下的spring.factories对应的EnableAutoConfi ...
- springcloud情操陶冶-springcloud config server(二)
承接前文springcloud情操陶冶-springcloud config server(一),本文将在前文的基础上讲解config server的涉外接口 前话 通过前文笔者得知,cloud co ...
- springcloud情操陶冶-springcloud config server(三)
承接前文springcloud情操陶冶-springcloud config server(二),本文就不讲述server了,就简单阐述下client的应用 前话 config server在引入的时 ...
- springcloud情操陶冶-springcloud config server(一)
承接前文springcloud情操陶冶-springcloud context(二),本文将在前文基础上浅析下ConfigServer的工作原理 前话 根据前文得知,bootstrapContext引 ...
- springboot情操陶冶-SpringApplication(二)
承接前文springboot情操陶冶-SpringApplication(一),本文将对run()方法作下详细的解析 SpringApplication#run() main函数经常调用的run()方 ...
- springcloud情操陶冶-初识springcloud
许久之前便听到了springcloud如雷贯耳的大名,但是不曾谋面,其主要应用于微服务的相关架构.笔者对微服务并不是很了解,但其既然比较出众,遂也稍微接触研究下 springcloud特性 sprin ...
- springboot情操陶冶-@Configuration注解解析
承接前文springboot情操陶冶-SpringApplication(二),本文将在前文的基础上分析下@Configuration注解是如何一步一步被解析的 @Configuration 如果要了 ...
- SpringMVC源码情操陶冶-DispatcherServlet简析(二)
承接前文SpringMVC源码情操陶冶-DispatcherServlet类简析(一),主要讲述初始化的操作,本文将简单介绍springmvc如何处理请求 DispatcherServlet#doDi ...
随机推荐
- USACO JAN14 奶牛冰壶运动 凸包+判定
满足条件的一定是在凸包内的,直接判断 恬不知耻的加了特判,2333 #include<cstdio> #include<iostream> #include<cstrin ...
- TensorFlow之DNN(二):全连接神经网络的加速技巧(Xavier初始化、Adam、Batch Norm、学习率衰减与梯度截断)
在上一篇博客<TensorFlow之DNN(一):构建“裸机版”全连接神经网络>中,我整理了一个用TensorFlow实现的简单全连接神经网络模型,没有运用加速技巧(小批量梯度下降不算哦) ...
- MySQL - 扩展性 2 扩展策略:氪金氪脑任君选
如果将应用的所有数据简单地放在一台 MySQL 服务器实例上,就不用谈什么扩展性了.但是业务能稳定持续的增长,那么应用肯定会碰到性能瓶颈. 对于很多类型的应用而言,购买更高性能的机器能解决一大部分性能 ...
- 彻底理解浏览器的缓存机制(http缓存机制)
一.概述 浏览器的缓存机制也就是我们说的HTTP缓存机制,其机制是根据HTTP报文的缓存标识进行的,所以在分析浏览器缓存机制之前,我们先使用图文简单介绍一下HTTP报文,HTTP报文分为两种: 同步s ...
- Python爬虫入门教程 57-100 python爬虫高级技术之验证码篇3-滑动验证码识别技术
滑动验证码介绍 本篇博客涉及到的验证码为滑动验证码,不同于极验证,本验证码难度略低,需要的将滑块拖动到矩形区域右侧即可完成. 这类验证码不常见了,官方介绍地址为:https://promotion.a ...
- WebApi管理和性能测试工具WebApiBenchmarks
说到WebApi管理和测试工具其实已经非常多的了,Postman.Swagger等在管理和维护上都非常出色:在性能测试方面也有不少的工具如:wrk,bombardier,http_load和ab等等. ...
- EFCore动态切换Schema
最近做个分库分表项目,用到schema的切换感觉还是有些坑的,在此分享下. 先简要说下我们的分库分表 分库分表规则 我定的规则是,订单号(数字)除以16,得出的结果为这个订单所在的数据库,然后他的余数 ...
- C# 跳转新的标签页
///这个是拿别人的,找到好多这个方法,溜了,不知道谁是原创 protected void btnPrint_Click(object sender, EventArgs e) { ...
- C++结构体与排列三平台出售
结构将不同的数据类型整合在一起构成一个新的类型,排列三平台出售(企 娥:217 1793 408)相当于数据中一条记录,比如学生结构体,整合了学好,姓名等信息.结构体的好处就是可以对这些信息进行整体管 ...
- 45个值得收藏的 CSS 形状
摘要: CSS炫技. 原文:45个值得收藏的 CSS 形状 作者:前端小智 Fundebug经授权转载,版权归原作者所有. CSS能够生成各种形状.正方形和矩形很容易,因为它们是 web 的自然形状. ...