主要分析 application.x 、@ConfigurationProperties 实现原理。
application.x,表示:x 表示文件后缀名,可以是 properties,yaml,xml,yml
application 配置文件
1、Spring bean 创建流程回顾
AbstractAutowireCapableBeanFactory
1、函数doCreateBean->createBeanInstance(beanName, mbd, args)
1、依据mbd 定义创建 bean instance,
2、将instance 封装到BeanWrapperImpl 中,为后续对象属性设值做准备。
3、这步只创建了实例,没有对实例的属性值绑定值。
2、doCreateBean->populateBean(beanName, mbd, instanceWrapper);
1、从mbd 中获取属性配置,PropertyValues
pvs=mbd.getPropertyValues()
2、依据,autowireByName,autowireByType 为 pvs 添加新的属性值。
3、applyPropertyValues(),beanWapper 将pvs 设值为对象的属性值。
4、这步以及获取到配置信息给bean 对象的属性设置值。
PlaceholderConfigurerSupport implements BeanFactoryPostProcessor
0、BeanFactoryPostProcessor 是bean 配置信息读取完后,首先执行的方法,可以对注册的bean 信息进行修改。
1、PlaceholderConfigurerSupport 实现了对bean 定义中 PropertyValues 进行扩展,属性值来源有两个方面。
1、属性的值来源与环境变量,private Environment environment;
2、属性的值来源于配置文件
doProcessProperties(): 属性值与BeanDefinition绑定
BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();
BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName);
// 将属性值设置到BeanDefinition 中
visitor.visitBeanDefinition(bd);
PlaceholderConfigurerSupport类图参考:
2、Spring boot 为PlaceholderConfigurerSupport 准备环境变量
1、SpringApplication#run
省略不相关代码
......
SpringApplicationRunListeners listeners = getRunListeners(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
.....
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
.....
ConfigurableEnvironment environment = getOrCreateEnvironment();
listeners.environmentPrepared(environment);
return environment;
...
}
看到listener,应该是观察者模式了。
SpringApplicationRunListeners 来源META-INF /spring.fatories:
在创建SpringApplication 对象时候读取,run方法之前。
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
2、listeners.environmentPrepared(environment)
基于SimpleApplicationEventMulticaster对SpringApplication里面所有ApplicationListener 进行相同的广播通知,通知的事件不一样。
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster
.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}
3、ApplicationListener来源于META-INF /spring.fatories
初始化读取
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
4、ConfigFileApplicationListener
配置文件有一个很重要的Listener,ConfigFileApplicationListener。这个类进行了application 属性文件的读取,Profile 判断,以及转换成ConfigurableEnvironment,提供给PlaceholderConfigurerSupport 使用。
ConfigFileApplicationListener 接受到事件通知
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
}
if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent(event);
}
}
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
List postProcessors = loadPostProcessors();
postProcessors.add(this);
AnnotationAwareOrderComparator.sort(postProcessors);
for (EnvironmentPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
}
}
EnvironmentPostProcessor 来源于META-INF /spring.factories 文件
,ConfigFileApplicationListener 本身也是一个EnvironmentPostProcessor,也是最核心的一个PostProcessor。postProcessors.add(this);
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor,\
org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor
ConfigFileApplicationListener#addPropertySources
进行application 文件解析。
protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
RandomValuePropertySource.addToEnvironment(environment);
new Loader(environment, resourceLoader).load();
}
new Loader()
Loader(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
.....
this.propertySourceLoaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class,
getClass().getClassLoader());
}
propertySourceLoaders解析xml,properties,yaml 格式,解析器来自META-INF /spring.factories
# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader
3、Spring boot 配置PlaceholderConfigurerSupport 注册
autoconfigure 项目文件META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
...autoconfigure.context.PropertyPlaceholderAutoConfiguration
@Configuration(proxyBeanMethods = false)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
public class PropertyPlaceholderAutoConfiguration {
@Bean
@ConditionalOnMissingBean(search = SearchStrategy.CURRENT)
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
小结:
ConfigFileApplicationListener 对application.x 文件进行读取,并且转换成环境变量,其中有很多地方对象都有来自于META-INF /spring.factories文件,比如,EnvironmentPostProcessor,PropertySourceLoader。autoconfigure 通过配置PropertySourcesPlaceholderConfigurer bean ,将boot 项目和spring 项目连通。环境变量信息一部分来来自于本身,另一部分来自于属性配置文件。
ConfigurationProperties 注解配置
入口:
autoconfigure 项目文件META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
autoconfigure.context.ConfigurationPropertiesAutoConfiguration
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
public class ConfigurationPropertiesAutoConfiguration {
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EnableConfigurationPropertiesRegistrar.class)
public @interface EnableConfigurationProperties {
String VALIDATOR_BEAN_NAME = "configurationPropertiesValidator";
Class>[] value() default {};
}
我们可以看到springboot 中只要注解是@EnableXXXXXX,一般都是用import 注解来导入配置信息的。
EnableConfigurationPropertiesRegistrar 类主要代码:
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
registerInfrastructureBeans(registry);
ConfigurationPropertiesBeanRegistrar beanRegistrar = new ConfigurationPropertiesBeanRegistrar(registry);
getTypes(metadata).forEach(beanRegistrar::register);
}
static void registerInfrastructureBeans(BeanDefinitionRegistry registry) {
ConfigurationPropertiesBindingPostProcessor.register(registry);
BoundConfigurationProperties.register(registry);
ConfigurationPropertiesBeanDefinitionValidator.register(registry);
ConfigurationBeanFactoryMetadata.register(registry);
}
EnableConfigurationPropertiesRegistrar主要注册了两个信息
1、注册ConfigurationPropertiesBindingPostProcessor ,对被@ConfigurationProperties注解的类,进行属性值绑定。
2、@EnableConfigurationProperties(arg),注册arg 的类当成一个普通bean。并且arg类被@ConfigurationProperties注解。因为@ConfigurationProperties注解的类要配合其他注解(@Configuration)才能注册到bean定义中,才能生效,如果使用@EnableConfigurationProperties(arg) ,EnableConfigurationPropertiesRegistrar 会将arg添加到bean 定义中,这样才能被ConfigurationPropertiesBindingPostProcessor 处理。
ConfigurationPropertiesBindingPostProcessor绑定值:
BindResult> bind(ConfigurationPropertiesBean propertiesBean) {
Bindable> target = propertiesBean.asBindTarget();
ConfigurationProperties annotation = propertiesBean.getAnnotation();
BindHandler bindHandler = getBindHandler(target, annotation);
return getBinder().bind(annotation.prefix(), target, bindHandler);
}
总结:
Spring boot 加强了默认属性的配置,并且还约定了配置文件application.x 名称。再一次明确约定大于配置的思想。spring boot通过扩展BeanPostProcessor ,如ConfigurationPropertiesBindingPostProcessor ,添加了@ConfigurationProperties注解的支持。还通过对application.x 文件解析,扩展了环境变量的值。明白属性值设置的原理,可以扩展如何将bean 对象的值,设置成自定义的值。也将有助于理解spring cloud 中属性值的配置 如bootstrap.x。
Spring 专题