SpringBoot - yml与properties配置文件及bean赋值

① SpringBoot的配置文件

SpringBoot使用一个全局的配置文件,配置文件名是固定的 :

配置文件的作用 : 修改SpringBoot自动配置的默认值(SpringBoot在底层已经配置好的属性)。


② yml 是什么?

YAML(YAML Ain’t Markup Language)
YAML A Markup Language:是一个标记语言
YAML isn’t Markup Language:不是一个标记语言;

YAML:以数据为中心,比json、xml等更适合做配置文件。

配置例子-更改Tomcat默认端口 :

server:port:8081

③ YAML语法

YAML使用缩进表示层级关系,缩进时不允许使用Tab键,只允许使用空格。缩进的空格的数目不重要,只要相同层级的元素左侧对齐即可。

YAML支持三种数据结构 :

语法格式如下 :

k:(空格)v;表示一对键值对,空格必须有。server:port: 8082

④ YAML值的写法

一般值有三种类型 : 字面量,即普通的值(数字,字符串,布尔);对象、map(键值对);数组(list set)。

(4.1)字面量

k: v:字面直接来写;

字符串默认不用加上单引号或者双引号;

“”:双引号;不会转义字符串里面的特殊字符;特殊字符会作为本身想表示的意思

name: "zhangsan \n lisi";输出:zhangsan 换行 lisi;

‘’:单引号;会转义特殊字符,特殊字符最终只是一个普通的字符串数据

name: ‘zhangsan \n lisi’; 输出:zhangsan \n lisi

(4.2)对象、map

k: v:在下一行来写对象的属性和值的关系;注意缩进
对象还是k: v的方式

friends:lastName: zhangsanage: 20

行内写法:

friends: {lastName: zhangsan,age: 18}

(4.3)数组

用- 值表示数组中的一个元素

pets:
‐ cat
‐ dog
‐ pig

行内写法

pets: [cat,dog,pig]

⑤ 使用yml为bean赋值

(5.1) 添加文件处理器依赖

官网如下 :
https://docs.spring.io/spring-boot/docs/2.0.2.RELEASE/reference/html/configuration-metadata.html#configuration-metadata-annotation-processor

<!‐‐导入配置文件处理器,配置文件进行绑定就会有提示‐‐>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional>
</dependency>


(5.2)JavaBean注解配置

@ConfigurationProperties:告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定。

prefix = "person":配置文件中哪个下面的所有属性进行一一映射。

该注解默认从全局配置文件中取值。

/**
* 将配置文件中配置的每一个属性的值,映射到这个组件中
* @ConfigurationProperties:告诉SpringBoot将本类中的所有属性
* 和配置文件中相关的配置进行绑定;
* prefix = "person":配置文件中哪个下面的所有属性进行一一映射
*
* 只有这个组件是容器中的组件,才能容器提供的@ConfigurationProperties功能;
*
*/
@Component
@ConfigurationProperties(prefix = "person")
public class Person {private String lastName;private Integer age;private Boolean boss;private Date birth;private Map<String,Object> maps;private List<Object> lists;private Dog dog;//...// 注意,@ConfigurationProperties该注解时不用再使用@Value!!!
}

(5.3)编写yml配置文件

server:port: 8082person:lastName: helloage: 18boss: falsebirth: 2017/12/12maps: {k1: v1,k2: 12}lists:‐ lisi‐ zhaoliudog:name: 小狗age: 12

(5.4)使用SpringBoot 测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbooHelloworldQuickApplicationTests {@AutowiredPerson person;@Testpublic void contextLoads() {System.out.println(person);}}

测试结果如下所示 :

Spring容器中的bean被yml中的配置正确赋值!


(5.5)使用@ConfigurationProperties注解的同时使用@Value

@Component
@ConfigurationProperties(prefix = "person")
public class Person {@Value("${person.age}")private String lastName;//...
}

如上所示,使用@Value为属性赋值别的变量的值。测试结果表明仍然为@ConfigurationProperties该注解为lastName赋值。


⑥ properties配置文件(仍旧使用@ConfigurationProperties)

properties配置文件是以前项目中常用的配置文件,SpringBoot同样保留了该种类型的配置文件。

如下所示,在properties文件中为person赋值:


# idea
person.age=21
person.birth=2018/11/11
person.last-name=小明
person.boss=true
person.dog.name=dog
person.dog.age=1
person.maps.k1=v1
person.maps.k2=v2
person.lists=a,b,c

**运行测试 : **

正常获取到值,但是中文乱码,为什么?

应该项目中都遇到这样的例子,读取properties文件中的中文乱码。以前解决办法就是将properties文件中的中文转换为Unicode形式,如\u822a\u6bcd。或者将其重新编码再解码。

idea中解决方法如下图:

  • 将其转换为ASCII,其与Unicode是可以相互转换的。

再次测试:


⑦ @Value为bean赋值

在以前的项目中常用为bean赋值(从properties文件中获取值)的方法有两种:

第一种-xml配置 :

 <bean id="urlModel" class="com.hh.core.model.UrlModel" ><property name="url" value="${url}"></property></bean>

第二种-@Value

@Component
public class Person {/*** <bean class="Person">*      <property name="lastName" value="字面量/${key}从环境变量、配置文件中获取值/#{SpEL}"></property>* <bean/>*///lastName必须是邮箱格式// @Email// 不支持JSR303校验@Value("${person.last-name}")//键必须与properties文件中的一致private String lastName;@Value("#{11*2}")//支持SpELl语法private Integer age;@Value("true")private Boolean boss;private Date birth;// @Value("${person.maps}")//不支持复杂类型封装private Map<String,Object> maps;private List<Object> lists;private Dog dog;//...
}

@Value默认从系统环境中加载属性变量。比如application.yml中配置了person.lastName属性,那么就可以使用@Value直接为Person的lastName赋值。


@Value注入map或者list

配置文件如下:


list: topic1,topic2,topic3
maps: "{key1: 'value1', key2: 'value2'}"

注入实例如下:

@Value("#{'${list}'.split(',')}")
private List<String> list;@Value("#{${maps}}")
private Map<String,String> maps;

⑧ @Value获取值和@ConfigurationProperties获取值比较

松散绑定 :

–person.firstName:使用标准方式
–person.first-name:大写用-
–person.first_name:大写用_
–PERSON_FIRST_NAME:
.推荐系统属性使用这种写法

上面几种写法在@ConfigurationProperties环境下都可以对应到person对象的firstName属性。@Value则必须保证取的键与properties文件中一致。


JSR303校验:

@Component
@ConfigurationProperties(prefix = "person")
@Validated
public class Person {//lastName必须是邮箱格式
//    @Value("${person.last-name}")@Emailprivate String lastName;//...
}

@Value 不支持JSR3030校验,但是支持SpELl语法,@ConfigurationProperties则相反。


对比总结如下:

总结如下:

配置文件yml还是properties他们都能获取到值;

如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,使用@Value;

如果说,我们专门编写了一个javaBean来和配置文件进行映射,我们就直接使用@ConfigurationProperties;

那么能否在业务逻辑类中使用@ConfigurationProperties呢?

不建议使用,@ConfigurationProperties会将本类中的所有属性和配置文件中相关的配置进行绑定。尤其@ConfigurationProperties支持松散语法。


⑨ @PropertySource加载指定的配置文件

将一切配置全部写在全局配置文件中,是不可想象的。项目中不可避免存在多个配置文件。

@PropertySource就可以根据需要加载指定的配置文件(@ConfigurationProperties 默认从全局配置文件获取配置),将配置文件中的属性注入到系统环境中。

这里将person的属性配置单独写在person.properties文件中,并从全局配置文件中注释掉person的属性配置。


Person中使用@Value为属性赋值:

@PropertySource(value = {"classpath:person.properties"})
@Component
public class Person {/*** <bean class="Person">*      <property name="lastName" value="字面量/${key}从环境变量、配置文件中获取值/#{SpEL}"></property>* <bean/>*///lastName必须是邮箱格式// @Email@Value("${person.last-name}")private String lastName;@Value("${person.age}")private Integer age;@Value("true")private Boolean boss;@Value("${person.birth}")private Date birth;@Value("${person.maps}")private Map<String,Object> maps;@Value("${person.lists}")private List<Object> lists;@Value("${person.dog}")private Dog dog;

为了对比person的属性从不同配置文件赋值,这里将全局配置文件中保留person.lastName属姓配置。

测试如下:

分析可知,默认从全局配置文件中为person赋值,这里为lastName赋值小明。

person的其他属性从person.properties文件中获取。


同时使用@PropertySource和@ConfigurationProperties注解,则默认属性仍旧从全局配置文件寻找,其次从@PropertySource指定的配置文件寻找。而且Person中的属性不用再使用@Value为其赋值。

@PropertySource(value = {"classpath:person.properties"})
@Component
@ConfigurationProperties(prefix = "person")
public class Person {private String lastName;private Integer age;private Boolean boss;//...
}

application.properties如下图:

person.properties如下图:

测试结果如下图:


⑩ 多个配置文件同属性配置@Value取值

如果项目中不同配置文件中配置同属性,使用@Value该如何取值呢?

– 这就涉及到了配置文件加载优先级的问题。

如图一:

application.properties与person.properties同时配置了属性person.last-name,如图中所示,使用@Value取值,此时取到的值为application.properties中的值。

若将application.properties中的person.last-name注释掉,则取的为person.properties(Person类配置了@PropertySource)值。


那么是否说明,默认从全局配置文件取还是按照上下顺序依次检查呢?

如图二所示:

修改application.properties为tapplication.properties文件,将会从application.yml到tapplication.properties依次查找,如找到该属性则取其值。

那么是否能够说明了配置文件的加载次序呢?

参考博客:SpringBoot配置文件加载位置与优先级。


(11)@ImportResource导入Spring配置文件

Spring Boot里面没有Spring的配置文件,我们自己编写的配置文件,也不能自动识别。那么如何使用我们自己编写的配置文件呢?

在主配置类添加@ImportResource注解,如下图:

配置文件内容如下:

 <bean id="helloService" class="com.web.service.HelloService"/>

测试如下:

在主配置类使用ImportResource引入自定义Spring配置文件,即可获取helloService bean。


(12)SpringBoot推荐给容器中添加组件的方式

SpringBoot推荐使用配置类的方式来给容器中添加组件。如下所示:

@Configuration
public class MyAppConfig {//将方法的返回值添加到容器中;容器中这个组件默认的id就是方法名@Beanpublic HelloService helloService(){System.out.println("配置类@Bean给容器中添加组件了...");return new HelloService();}
}

测试结果如下图:


(13)配置文件占位符

除了前面说的几种方式,还可以使用占位符的方式在配置文件中为属性赋值。

① 随机数

示例如下:

person.last‐name=张三${random.uuid}

② 占位符获取之前配置的值,如果没有可以是用:指定默认值

示例如下:

person.last‐name=张三${random.uuid}
person.age=${random.int}
person.birth=2017/12/15
person.boss=false
person.maps.k1=v1
person.maps.k2=14
person.lists=a,b,c
person.dog.name=${person.hello:hello}_dog
person.dog.age=15

${person.hello:hello}意思为如果person.hello没有值则默认赋值为hello。${person.hello}如果有值,则取值,无值则会当作字面量解析–${person.hello}原样赋值。


(14)@PropertySource和@ConfigurationProperties以及@Value

这三个注解究竟是什么,做了什么?

① @Value

源码如下:

/*** Annotation at the field or method/constructor parameter level* that indicates a default value expression for the affected argument.** <p>Typically used for expression-driven dependency injection. Also supported* for dynamic resolution of handler method parameters, e.g. in Spring MVC.** <p>A common use case is to assign default field values using* "#{systemProperties.myProp}" style expressions.** <p>Note that actual processing of the {@code @Value} annotation is performed* by a {@link org.springframework.beans.factory.config.BeanPostProcessor* BeanPostProcessor} which in turn means that you <em>cannot</em> use* {@code @Value} within* {@link org.springframework.beans.factory.config.BeanPostProcessor* BeanPostProcessor} or* {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor BeanFactoryPostProcessor}* types. Please consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor}* class (which, by default, checks for the presence of this annotation).** @author Juergen Hoeller* @since 3.0* @see AutowiredAnnotationBeanPostProcessor* @see Autowired* @see org.springframework.beans.factory.config.BeanExpressionResolver* @see org.springframework.beans.factory.support.AutowireCandidateResolver#getSuggestedValue*/
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {/*** The actual value expression: e.g. "#{systemProperties.myProp}".*/String value();}

言简意赅说一下,这个注解可以动态为属性赋值,处理过程是BeanPostProcessor!


② @PropertySource

源码如下:

/*** Annotation providing a convenient and declarative mechanism for adding a* {@link org.springframework.core.env.PropertySource PropertySource} to Spring's* {@link org.springframework.core.env.Environment Environment}. To be used in* conjunction with @{@link Configuration} classes.** <h3>Example usage</h3>** <p>Given a file {@code app.properties} containing the key/value pair* {@code testbean.name=myTestBean}, the following {@code @Configuration} class* uses {@code @PropertySource} to contribute {@code app.properties} to the* {@code Environment}'s set of {@code PropertySources}.** <pre class="code">* @Configuration* @PropertySource("classpath:/com/myco/app.properties")* public class AppConfig {*     @Autowired*     Environment env;**     @Bean*     public TestBean testBean() {*         TestBean testBean = new TestBean();*         testBean.setName(env.getProperty("testbean.name"));*         return testBean;*     }* }</pre>** Notice that the {@code Environment} object is @{@link* org.springframework.beans.factory.annotation.Autowired Autowired} into the* configuration class and then used when populating the {@code TestBean} object. Given* the configuration above, a call to {@code testBean.getName()} will return "myTestBean".** <h3>Resolving ${...} placeholders in {@code <bean>} and {@code @Value} annotations</h3>** In order to resolve ${...} placeholders in {@code <bean>} definitions or {@code @Value}* annotations using properties from a {@code PropertySource}, one must register* a {@code PropertySourcesPlaceholderConfigurer}. This happens automatically when using* {@code <context:property-placeholder>} in XML, but must be explicitly registered using* a {@code static} {@code @Bean} method when using {@code @Configuration} classes. See* the "Working with externalized values" section of @{@link Configuration}'s javadoc and* "a note on BeanFactoryPostProcessor-returning @Bean methods" of @{@link Bean}'s javadoc* for details and examples.** <h3>Resolving ${...} placeholders within {@code @PropertySource} resource locations</h3>** Any ${...} placeholders present in a {@code @PropertySource} {@linkplain #value()* resource location} will be resolved against the set of property sources already* registered against the environment. For example:** <pre class="code">* @Configuration* @PropertySource("classpath:/com/${my.placeholder:default/path}/app.properties")* public class AppConfig {*     @Autowired*     Environment env;**     @Bean*     public TestBean testBean() {*         TestBean testBean = new TestBean();*         testBean.setName(env.getProperty("testbean.name"));*         return testBean;*     }* }</pre>** Assuming that "my.placeholder" is present in one of the property sources already* registered, e.g. system properties or environment variables, the placeholder will* be resolved to the corresponding value. If not, then "default/path" will be used as a* default. Expressing a default value (delimited by colon ":") is optional.  If no* default is specified and a property cannot be resolved, an {@code* IllegalArgumentException} will be thrown.** <h3>A note on property overriding with @PropertySource</h3>** In cases where a given property key exists in more than one {@code .properties}* file, the last {@code @PropertySource} annotation processed will 'win' and override.** For example, given two properties files {@code a.properties} and* {@code b.properties}, consider the following two configuration classes* that reference them with {@code @PropertySource} annotations:** <pre class="code">* @Configuration* @PropertySource("classpath:/com/myco/a.properties")* public class ConfigA { }** @Configuration* @PropertySource("classpath:/com/myco/b.properties")* public class ConfigB { }* </pre>** The override ordering depends on the order in which these classes are registered* with the application context.* <pre class="code">* AnnotationConfigApplicationContext ctx =*     new AnnotationConfigApplicationContext();* ctx.register(ConfigA.class);* ctx.register(ConfigB.class);* ctx.refresh();* </pre>** In the scenario above, the properties in {@code b.properties} will override any* duplicates that exist in {@code a.properties}, because {@code ConfigB} was registered* last.** <p>In certain situations, it may not be possible or practical to tightly control* property source ordering when using {@code @ProperySource} annotations. For example,* if the {@code @Configuration} classes above were registered via component-scanning,* the ordering is difficult to predict. In such cases - and if overriding is important -* it is recommended that the user fall back to using the programmatic PropertySource API.* See {@link org.springframework.core.env.ConfigurableEnvironment ConfigurableEnvironment}* and {@link org.springframework.core.env.MutablePropertySources MutablePropertySources}* javadocs for details.** @author Chris Beams* @author Juergen Hoeller* @author Phillip Webb* @since 3.1* @see PropertySources* @see Configuration* @see org.springframework.core.env.PropertySource* @see org.springframework.core.env.ConfigurableEnvironment#getPropertySources()* @see org.springframework.core.env.MutablePropertySources*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(PropertySources.class)
public @interface PropertySource {/*** Indicate the name of this property source. If omitted, a name will* be generated based on the description of the underlying resource.* @see org.springframework.core.env.PropertySource#getName()* @see org.springframework.core.io.Resource#getDescription()*/String name() default "";/*** Indicate the resource location(s) of the properties file to be loaded.* For example, {@code "classpath:/com/myco/app.properties"} or* {@code "file:/path/to/file"}.* <p>Resource location wildcards (e.g. **/*.properties) are not permitted;* each location must evaluate to exactly one {@code .properties} resource.* <p>${...} placeholders will be resolved against any/all property sources already* registered with the {@code Environment}. See {@linkplain PropertySource above}* for examples.* <p>Each location will be added to the enclosing {@code Environment} as its own* property source, and in the order declared.*/String[] value();/*** Indicate if failure to find the a {@link #value() property resource} should be* ignored.* <p>{@code true} is appropriate if the properties file is completely optional.* Default is {@code false}.* @since 4.0*/boolean ignoreResourceNotFound() default false;/*** A specific character encoding for the given resources, e.g. "UTF-8".* @since 4.3*/String encoding() default "";/*** Specify a custom {@link PropertySourceFactory}, if any.* <p>By default, a default factory for standard resource files will be used.* @since 4.3* @see org.springframework.core.io.support.DefaultPropertySourceFactory* @see org.springframework.core.io.support.ResourcePropertySource*/Class<? extends PropertySourceFactory> factory() default PropertySourceFactory.class;}

言简意赅说明一下,该注解将制定文件中的key/value形式的属性配置注入到了Environment中!


③ @ConfigurationProperties

@ConfigurationProperties源码如下:

/*** Annotation for externalized configuration. Add this to a class definition or a* {@code @Bean} method in a {@code @Configuration} class if you want to bind and validate* some external Properties (e.g. from a .properties file).* <p>* Note that contrary to {@code @Value}, SpEL expressions are not evaluated since property* values are externalized.** @author Dave Syer* @see ConfigurationPropertiesBindingPostProcessor* @see EnableConfigurationProperties*/
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ConfigurationProperties {/*** The name prefix of the properties that are valid to bind to this object. Synonym* for {@link #prefix()}.* @return the name prefix of the properties to bind*/@AliasFor("prefix")String value() default "";/*** The name prefix of the properties that are valid to bind to this object. Synonym* for {@link #value()}.* @return the name prefix of the properties to bind*/@AliasFor("value")String prefix() default "";/*** Flag to indicate that when binding to this object invalid fields should be ignored.* Invalid means invalid according to the binder that is used, and usually this means* fields of the wrong type (or that cannot be coerced into the correct type).* @return the flag value (default false)*/boolean ignoreInvalidFields() default false;/*** Flag to indicate that when binding to this object fields with periods in their* names should be ignored.* @return the flag value (default false)*/boolean ignoreNestedProperties() default false;/*** Flag to indicate that when binding to this object unknown fields should be ignored.* An unknown field could be a sign of a mistake in the Properties.* @return the flag value (default true)*/boolean ignoreUnknownFields() default true;/*** Flag to indicate that an exception should be raised if a Validator is available,* the class is annotated with {@link Validated @Validated} and validation fails. If* it is set to false, validation errors will be swallowed. They will be logged, but* not propagated to the caller.* @return the flag value (default true)* @deprecated as of 1.5 since validation only kicks in when {@code @Validated} is* present*/@Deprecatedboolean exceptionIfInvalid() default true;}

功能自己看源码上面的javadoc,这里需要注意的是ConfigurationPropertiesBindingPostProcessor。

很熟悉吧,又是一个后置处理器!

ConfigurationPropertiesBindingPostProcessor源码如下:

public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProcessor,BeanFactoryAware, EnvironmentAware, ApplicationContextAware, InitializingBean,DisposableBean, ApplicationListener<ContextRefreshedEvent>, PriorityOrdered {/*** The bean name of the configuration properties validator.*/public static final String VALIDATOR_BEAN_NAME = "configurationPropertiesValidator";private static final String[] VALIDATOR_CLASSES = { "javax.validation.Validator","javax.validation.ValidatorFactory","javax.validation.bootstrap.GenericBootstrap" };private static final Log logger = LogFactory.getLog(ConfigurationPropertiesBindingPostProcessor.class);private ConfigurationBeanFactoryMetaData beans = new ConfigurationBeanFactoryMetaData();private PropertySources propertySources;private Validator validator;private volatile Validator localValidator;private ConversionService conversionService;private DefaultConversionService defaultConversionService;private BeanFactory beanFactory;private Environment environment = new StandardEnvironment();private ApplicationContext applicationContext;private List<Converter<?, ?>> converters = Collections.emptyList();private List<GenericConverter> genericConverters = Collections.emptyList();private int order = Ordered.HIGHEST_PRECEDENCE + 1;/*** A list of custom converters (in addition to the defaults) to use when converting* properties for binding.* @param converters the converters to set*/@Autowired(required = false)@ConfigurationPropertiesBindingpublic void setConverters(List<Converter<?, ?>> converters) {this.converters = converters;}/*** A list of custom converters (in addition to the defaults) to use when converting* properties for binding.* @param converters the converters to set*/@Autowired(required = false)@ConfigurationPropertiesBindingpublic void setGenericConverters(List<GenericConverter> converters) {this.genericConverters = converters;}/*** Set the order of the bean.* @param order the order*/public void setOrder(int order) {this.order = order;}/*** Return the order of the bean.* @return the order*/@Overridepublic int getOrder() {return this.order;}/*** Set the property sources to bind.* @param propertySources the property sources*/public void setPropertySources(PropertySources propertySources) {this.propertySources = propertySources;}/*** Set the bean validator used to validate property fields.* @param validator the validator*/public void setValidator(Validator validator) {this.validator = validator;}/*** Set the conversion service used to convert property values.* @param conversionService the conversion service*/public void setConversionService(ConversionService conversionService) {this.conversionService = conversionService;}/*** Set the bean meta-data store.* @param beans the bean meta data store*/public void setBeanMetaDataStore(ConfigurationBeanFactoryMetaData beans) {this.beans = beans;}@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {this.beanFactory = beanFactory;}@Overridepublic void setEnvironment(Environment environment) {this.environment = environment;}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) {this.applicationContext = applicationContext;}@Overridepublic void afterPropertiesSet() throws Exception {if (this.propertySources == null) {this.propertySources = deducePropertySources();}if (this.validator == null) {this.validator = getOptionalBean(VALIDATOR_BEAN_NAME, Validator.class);}if (this.conversionService == null) {this.conversionService = getOptionalBean(ConfigurableApplicationContext.CONVERSION_SERVICE_BEAN_NAME,ConversionService.class);}}@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {freeLocalValidator();}@Overridepublic void destroy() throws Exception {freeLocalValidator();}private void freeLocalValidator() {try {Validator validator = this.localValidator;this.localValidator = null;if (validator != null) {((DisposableBean) validator).destroy();}}catch (Exception ex) {throw new IllegalStateException(ex);}}private PropertySources deducePropertySources() {PropertySourcesPlaceholderConfigurer configurer = getSinglePropertySourcesPlaceholderConfigurer();if (configurer != null) {// Flatten the sources into a single list so they can be iteratedreturn new FlatPropertySources(configurer.getAppliedPropertySources());}if (this.environment instanceof ConfigurableEnvironment) {MutablePropertySources propertySources = ((ConfigurableEnvironment) this.environment).getPropertySources();return new FlatPropertySources(propertySources);}// empty, so not very useful, but fulfils the contractlogger.warn("Unable to obtain PropertySources from "+ "PropertySourcesPlaceholderConfigurer or Environment");return new MutablePropertySources();}private PropertySourcesPlaceholderConfigurer getSinglePropertySourcesPlaceholderConfigurer() {// Take care not to cause early instantiation of all FactoryBeansif (this.beanFactory instanceof ListableBeanFactory) {ListableBeanFactory listableBeanFactory = (ListableBeanFactory) this.beanFactory;Map<String, PropertySourcesPlaceholderConfigurer> beans = listableBeanFactory.getBeansOfType(PropertySourcesPlaceholderConfigurer.class, false,false);if (beans.size() == 1) {return beans.values().iterator().next();}if (beans.size() > 1 && logger.isWarnEnabled()) {logger.warn("Multiple PropertySourcesPlaceholderConfigurer "+ "beans registered " + beans.keySet()+ ", falling back to Environment");}}return null;}private <T> T getOptionalBean(String name, Class<T> type) {try {return this.beanFactory.getBean(name, type);}catch (NoSuchBeanDefinitionException ex) {return null;}}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName)throws BeansException {ConfigurationProperties annotation = AnnotationUtils.findAnnotation(bean.getClass(), ConfigurationProperties.class);if (annotation != null) {postProcessBeforeInitialization(bean, beanName, annotation);}annotation = this.beans.findFactoryAnnotation(beanName,ConfigurationProperties.class);if (annotation != null) {postProcessBeforeInitialization(bean, beanName, annotation);}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName)throws BeansException {return bean;}@SuppressWarnings("deprecation")private void postProcessBeforeInitialization(Object bean, String beanName,ConfigurationProperties annotation) {Object target = bean;PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory<Object>(target);factory.setPropertySources(this.propertySources);factory.setValidator(determineValidator(bean));// If no explicit conversion service is provided we add one so that (at least)// comma-separated arrays of convertibles can be bound automaticallyfactory.setConversionService(this.conversionService == null? getDefaultConversionService() : this.conversionService);if (annotation != null) {factory.setIgnoreInvalidFields(annotation.ignoreInvalidFields());factory.setIgnoreUnknownFields(annotation.ignoreUnknownFields());factory.setExceptionIfInvalid(annotation.exceptionIfInvalid());factory.setIgnoreNestedProperties(annotation.ignoreNestedProperties());if (StringUtils.hasLength(annotation.prefix())) {factory.setTargetName(annotation.prefix());}}try {factory.bindPropertiesToTarget();}catch (Exception ex) {String targetClass = ClassUtils.getShortName(target.getClass());throw new BeanCreationException(beanName, "Could not bind properties to "+ targetClass + " (" + getAnnotationDetails(annotation) + ")", ex);}}private String getAnnotationDetails(ConfigurationProperties annotation) {if (annotation == null) {return "";}StringBuilder details = new StringBuilder();details.append("prefix=").append(annotation.prefix());details.append(", ignoreInvalidFields=").append(annotation.ignoreInvalidFields());details.append(", ignoreUnknownFields=").append(annotation.ignoreUnknownFields());details.append(", ignoreNestedProperties=").append(annotation.ignoreNestedProperties());return details.toString();}private Validator determineValidator(Object bean) {Validator validator = getValidator();boolean supportsBean = (validator != null && validator.supports(bean.getClass()));if (ClassUtils.isAssignable(Validator.class, bean.getClass())) {if (supportsBean) {return new ChainingValidator(validator, (Validator) bean);}return (Validator) bean;}return (supportsBean ? validator : null);}private Validator getValidator() {if (this.validator != null) {return this.validator;}if (this.localValidator == null && isJsr303Present()) {this.localValidator = new ValidatedLocalValidatorFactoryBean(this.applicationContext);}return this.localValidator;}private boolean isJsr303Present() {for (String validatorClass : VALIDATOR_CLASSES) {if (!ClassUtils.isPresent(validatorClass,this.applicationContext.getClassLoader())) {return false;}}return true;}private ConversionService getDefaultConversionService() {if (this.defaultConversionService == null) {DefaultConversionService conversionService = new DefaultConversionService();this.applicationContext.getAutowireCapableBeanFactory().autowireBean(this);for (Converter<?, ?> converter : this.converters) {conversionService.addConverter(converter);}for (GenericConverter genericConverter : this.genericConverters) {conversionService.addConverter(genericConverter);}this.defaultConversionService = conversionService;}return this.defaultConversionService;}/*** {@link LocalValidatorFactoryBean} supports classes annotated with* {@link Validated @Validated}.*/private static class ValidatedLocalValidatorFactoryBeanextends LocalValidatorFactoryBean {private static final Log logger = LogFactory.getLog(ConfigurationPropertiesBindingPostProcessor.class);ValidatedLocalValidatorFactoryBean(ApplicationContext applicationContext) {setApplicationContext(applicationContext);setMessageInterpolator(new MessageInterpolatorFactory().getObject());afterPropertiesSet();}@Overridepublic boolean supports(Class<?> type) {if (!super.supports(type)) {return false;}if (AnnotatedElementUtils.hasAnnotation(type, Validated.class)) {return true;}if (type.getPackage() != null && type.getPackage().getName().startsWith("org.springframework.boot")) {return false;}if (getConstraintsForClass(type).isBeanConstrained()) {logger.warn("The @ConfigurationProperties bean " + type+ " contains validation constraints but had not been annotated "+ "with @Validated.");}return true;}}/*** {@link Validator} implementation that wraps {@link Validator} instances and chains* their execution.*/private static class ChainingValidator implements Validator {private Validator[] validators;ChainingValidator(Validator... validators) {Assert.notNull(validators, "Validators must not be null");this.validators = validators;}@Overridepublic boolean supports(Class<?> clazz) {for (Validator validator : this.validators) {if (validator.supports(clazz)) {return true;}}return false;}@Overridepublic void validate(Object target, Errors errors) {for (Validator validator : this.validators) {if (validator.supports(target.getClass())) {validator.validate(target, errors);}}}}/*** Convenience class to flatten out a tree of property sources without losing the* reference to the backing data (which can therefore be updated in the background).*/private static class FlatPropertySources implements PropertySources {private PropertySources propertySources;FlatPropertySources(PropertySources propertySources) {this.propertySources = propertySources;}@Overridepublic Iterator<PropertySource<?>> iterator() {MutablePropertySources result = getFlattened();return result.iterator();}@Overridepublic boolean contains(String name) {return get(name) != null;}@Overridepublic PropertySource<?> get(String name) {return getFlattened().get(name);}private MutablePropertySources getFlattened() {MutablePropertySources result = new MutablePropertySources();for (PropertySource<?> propertySource : this.propertySources) {flattenPropertySources(propertySource, result);}return result;}private void flattenPropertySources(PropertySource<?> propertySource,MutablePropertySources result) {Object source = propertySource.getSource();if (source instanceof ConfigurableEnvironment) {ConfigurableEnvironment environment = (ConfigurableEnvironment) source;for (PropertySource<?> childSource : environment.getPropertySources()) {flattenPropertySources(childSource, result);}}else {result.addLast(propertySource);}}}}

可以发现这个类实现了我们很多眼熟的接口:

public class ConfigurationPropertiesBindingPostProcessor implements
BeanPostProcessor,  BeanFactoryAware, EnvironmentAware,
ApplicationContextAware, InitializingBean,DisposableBean,
ApplicationListener<ContextRefreshedEvent>, PriorityOrdered {
//...
}

大概就是在bean的属性赋值、初始化前后进行的操作,具体参考博文bean的初始化和销毁过程详解。

SpringBoot - yml与properties配置文件及bean赋值相关推荐

  1. IDEA springboot项目中properties配置文件 {针对将对应GBK改为UTF-8并勾选转为ASCII后仍无效情况} 运行时中文乱码解决

    springboot项目中properties配置文件中,运行时中文乱码情况 file encoding里边进行设置,设为utf-8并勾选转为ascii,分别在setting.setting for ...

  2. SpringBoot 基于配置文件给bean赋值

    方式一.使用yaml文件对bean进行注入 案例: (先来两个实体类做为案例测试用) Car类 @Component public class Car {String name;String pinp ...

  3. SpringBoot解析yml/yaml/properties配置文件的四种方式汇总

    目录 一.配置文件注入方式一@Value 二.配置文件注入方式二@ConfigurationProperties 三.自定义解析类,直接暴力读取yml配置文件 四.Spring配置文件的解析类Envi ...

  4. @Value直接将yml或者properties配置文件的字符串分割成数组。

    将配置文件属性分割成数组. 使用注解: @Value("#{'${yourConfName}'.split(',')}") private List<String> w ...

  5. properties配置文件和yml配置文件互相转换

    原因: 在现有的API中只找到了读取yml配置文件转化为properties形式,未找到properties格式文件,网上其他人写的测试后都有各种各样的bug,于是就自己手动重新编写一个. 目标: 1 ...

  6. maven 不编译jasper文件_第一个SpringBoot项目、核心配置文件properties(yml、yaml)、集成jsp...

    SpringBoot简介及国内关注度 SpringBoot简介: 它用来简化 Spring 应用程序的创建和开发过程,也可以说 Spring Boot 能简化我们之前采用 SpringMVC +Spr ...

  7. jsp拿不到回显数据_第一个SpringBoot项目、核心配置文件properties(yml、yaml)、集成jsp...

    SpringBoot简介及国内关注度 SpringBoot简介: 它用来简化 Spring 应用程序的创建和开发过程,也可以说 Spring Boot 能简化我们之前采用 SpringMVC +Spr ...

  8. Spring Boot 配置文件 yml与properties

    原文链接:https://blog.csdn.net/qq_33524158/article/details/79600434 1.配置文件 SpringBoot使用一个全局的配置文件,配置文件名是固 ...

  9. SpringBoot学习:读取yml和properties文件的内容

    一.在SpringBoot实现属性注入: 1).添加pom依赖jar包: 1 <!-- 支持 @ConfigurationProperties 注解 --> 2 <!-- https ...

最新文章

  1. 2_tabbar底部切换
  2. IIS的应用程序池优化方法
  3. QT的QWhatsThis类的使用
  4. 张恩民 php,php100教程_php100张恩民php视频 56课时_网站编程_寂涯网络学习基地
  5. Eureke服务入门就这一篇就够了
  6. 6. Zend_Uri
  7. 同花顺开放接口api_接口大师,即刻构建你的OpenAPI+开放平台
  8. Phase seperation 的无序结构域(IDRs)怎么预测?
  9. 计算机硬盘最小容量是多少,通常计算机的存储容量是多少?
  10. 手把手带你用Python完成一个数据分析项目,能写进简历,拿走不谢!(另送15个实战案例)...
  11. 拓嘉启远:拼多多前期没有流量如何补充
  12. 中科院计算所王永庆详解IJCAI 17录用论文:如何用注意力机制RNN进行信息传播建模?|IJCAI 2017...
  13. Linux之USB无线网卡开发(二)
  14. ntpd服务状态及日志查询方式
  15. 记录chrome 浏览器 本地ip 地址报 CORS 错误
  16. java八大数据类型_java的八大基本数据类型分别是什么?
  17. websocket自动重连
  18. .NET北京俱乐部,技术的饕餮盛宴,不枉此行
  19. DxO PhotoLab 2.2.2完整精华汉化版|顶级RAW数码后期软件
  20. uniapp GPS定位功能的实现

热门文章

  1. 9001.消息中间件zeroMQ
  2. 【MATLAB、深度学习】AlexNet及VGG神经网络在MATLAB上的应用
  3. STC51-串口通信
  4. 基于平面 marker 的 Bundle Adjustmet
  5. ubuntu 安装使用多版本opencv
  6. UDP与TCP对比,TCP保证可靠性传输的详细说明
  7. oracle 数据库bak文件怎么打开,Oracle数据库的参数文件备份与恢复
  8. php 一直运行页面,为什么浏览器关闭后PHP还会一直执行啊
  9. 【重难点】【Java集合 04】ArrayDeque 的使用场景、ArrayBlockingQueue
  10. 微信小程序|开发实战篇之三