Spring boot | 属性配置

主要分析 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类图参考:


PlaceholderConfigurerSupport.png
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 专题

你可能感兴趣的:(Spring boot | 属性配置)