To undertake the former Wen springboot sentiment edify [email protected] annotation analysis, this article will be based on the previous article on the use of @configurationproperties annotations
@ConfigurationProperties
This annotation is used to load the configuration file and map the corresponding values to the corresponding Java attributes, such as the following
1. Configuration Properties Specify application.properties
# user customuser.custom.username=demo_jinguser.custom.nickname=nanco[email protected]user.custom.password=demo1234user.custom.job=programmer
2. Attribute mapping class (using @configurationproperties annotations)Userproperty.java
Package Com.example.demo.bootbase;import org.springframework.boot.context.properties.configurationproperties;/** * @author Nanco * @create 2018/8/13 **/@ConfigurationProperties (prefix = "User.custom") public class UserProperty {Priv Ate String username; Private String nickname; Private String Email; private String password; Private String job; Public String GetUserName () {return username; } public void Setusername (String username) {this.username = username; } public String Getnickname () {return nickname; } public void Setnickname (String nickname) {this.nickname = nickname; } public String Getemail () {return email; } public void Setemail (String email) {this.email = email; } public String GetPassword () {return password; } public void SetPassword (String password) {this.password = password; } public String Getjob () {return job; } public void Setjob (String job) {this.job = job; } @Override Public String toString () {return ' userproperty{' + ' username= ' + username + ' \ ' + ", nickname= '" + nickname + "\" + ", email=" + email + "\" + ", Passwor D= ' + password + ' \ ' + ', job= ' + job + ' \ ' + '} '; }}
3. Attribute mapping on (using @enableconfigurationproperties annotations)Userpropertiesautoconfiguration.java
package com.example.demo.bootbase;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.context.annotation.Configuration;/** * @author nanco * @create 2018/8/13 **/@Configuration@EnableConfigurationProperties(value = UserProperty.class)public class UserPropertiesAutoConfiguration {}
4. The above annotations come into effect entrance meta-inf\spring.fatories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.demo.bootbase.UserPropertiesAutoConfiguration
5. Results test
package com.example.demo;import com.example.demo.bootbase.UserProperty;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.ApplicationContext;@SpringBootApplicationpublic class DemoSpringbootApplication { public static void main(String[] args) { ApplicationContext demoApplicationContext = SpringApplication.run(DemoSpringbootApplication.class, args); UserProperty userProperty = demoApplicationContext.getBean(UserProperty.class) ; System.out.println(userProperty); }}
The output is as follows
......2018-08-13 14:37:05.537 INFO 17384 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 21474836472018-08-13 14:37:05.546 INFO 17384 --- [ main] c.e.demo.DemoSpringbootApplication : Started DemoSpringbootApplication in 2.611 seconds (JVM running for 3.756)UserProperty{username='demo_jing', nickname='nanco', email='[email protected]', password='demo1234', job='programmer'}
The results appear as we have predicted, and the attributes are given accordingly. Below the author to carry out the analysis of the source layer to solve the binding of the small mystery
@EnableConfigurationProperties
To make the above results run successfully, you must use annotations in the corresponding startup class @EnableConfigurationProperties
, let's look at their source code
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Import(EnableConfigurationPropertiesImportSelector.class)public @interface EnableConfigurationProperties { /** * Convenient way to quickly register {@link ConfigurationProperties} annotated beans * with Spring. Standard Spring Beans will also be scanned regardless of this value. * @return {@link ConfigurationProperties} annotated beans to register */ Class<?>[] value() default {};}
The value property is the scanned property class, and the specified class attribute is registered to the Bean factory. Through the previous analysis can be obtained, the final analysis is through the @Import introduced by the Enableconfigurationpropertiesimportselector.class to achieve
Enableconfigurationpropertiesimportselector
View the selectimports () method of its replication directly
private static final String[] IMPORTS = { // 属性类注册 ConfigurationPropertiesBeanRegistrar.class.getName(), // 属性类绑定处理 ConfigurationPropertiesBindingPostProcessorRegistrar.class.getName() }; @Override public String[] selectImports(AnnotationMetadata metadata) { return IMPORTS; }
Two classes will be imported to handle the relationship of the attributes, and we analyze them in order
Configurationpropertiesbeanregistrar.class
To look directly at the way it's being replicated.
@Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { // 读取被注解类上的EnableConfigurationProperties上的value属性并进行注入至bean工厂 getTypes(metadata).forEach((type) -> register(registry, (ConfigurableListableBeanFactory) registry, type)); }
The specific code is not posted out, the author here to make a small summary
First read @EnableConfigurationProperties
the value property on the annotated class
Before injecting the class set specified in the value attribute above to the Bean factory, it is preferable to determine if the annotation has been @ConfigurationProperties
modified and no error will be given.
Registers the specified class collection to the Bean factory
Configurationpropertiesbindingpostprocessorregistrar
Direct view of the replication method
@Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { if (!registry.containsBeanDefinition( ConfigurationPropertiesBindingPostProcessor.BEAN_NAME)) { // ConfigurationPropertiesBindingPostProcessor注册 registerConfigurationPropertiesBindingPostProcessor(registry); // ConfigurationBeanFactoryMetadata注册 registerConfigurationBeanFactoryMetadata(registry); } }
The main registered two beandefinition, namely the Configurationpropertiesbindingpostprocessor class and Configurationbeanfactorymetadata class.
It seems that the specific attribute binding is the two classes to deal with, the author continues to analyze
Configurationbeanfactorymetadata
Implementation of the Postprocessbeanfactory () method in the Beanfactorypostprocessor interface class takes precedence based on the life cycle of the spring bean
@Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; for (String name : beanFactory.getBeanDefinitionNames()) { BeanDefinition definition = beanFactory.getBeanDefinition(name); String method = definition.getFactoryMethodName(); String bean = definition.getFactoryBeanName(); if (method != null && bean != null) { this.beansFactoryMetadata.put(name, new FactoryMetadata(bean, method)); } } }
It is mainly used to obtain the beandefinitions of implementing the Factorybean interface on the Bean factory and save it to the beansfactorymetadata property.
Configurationpropertiesbindingpostprocessor
Based on the spring Bean's life cycle, we first look at its afterpropertiesset () implementation method
@Override public void afterPropertiesSet() throws Exception { // 获取ConfigurationBeanFactoryMetadata实体类 this.beanFactoryMetadata = this.applicationContext.getBean( ConfigurationBeanFactoryMetadata.BEAN_NAME, ConfigurationBeanFactoryMetadata.class); // 创建属性绑定类 this.configurationPropertiesBinder = new ConfigurationPropertiesBinder( this.applicationContext, VALIDATOR_BEAN_NAME); }
And then we look at the postprocessbeforeinitialization () method
@Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { // 查找是否bean上对应的class上含有ConfigurationProperties注解 ConfigurationProperties annotation = getAnnotation(bean, beanName, ConfigurationProperties.class); if (annotation != null) { // 开始绑定操作 bind(bean, beanName, annotation); } return bean; }
Ok, we continue to follow the bind () method
private void bind (Object bean, String beanname, configurationproperties annotation) {R Esolvabletype type = Getbeantype (bean, beanname); See if the class contains @validated annotations Validated Validated = getannotation (Bean, beanname, validated.class); annotation[] Annotations = (validated! = null? New annotation[] {Annotation, validated}: New annotation[] {Annotation}); class/instances/Annotations Three are bound together for the following calls bindable<?> target = Bindable.of (type). Withexistingvalue (Bean). WI Thannotations (annotations); try {this.configurationPropertiesBinder.bind (target); } catch (Exception ex) {throw new Configurationpropertiesbindexception (Beanname, bean, annotation, ex); } }
The final how to bind this article does not explain, involved in a lot of code, interested readers can analyze their own.
It is obvious that it will read the unified configuration of springboot such as application.properties\application.yml applied to @ConfigurationProperties
annotations
Summary
If you want to use an external source's property value in Springboot, there are two methods
@PropertySource
Annotations load external sources and then @Value
inject them with annotations
@ConfigurationProperties
The annotation adornment JavaBean, whose prefix property is required, must be configured, and the internal properties of JavaBean must be consistent with the properties specified by the configuration file, and the setter method has to be configured to ensure that the property setting succeeds;
And you must use @EnableConfigurationProperties
annotations to associate the above JavaBean class with its value property
Springboot sentiment edify [email protected] annotation Analysis