Spring 配置解析之Properties
1.简单示例:
SpringBoot中的的配置简单属性类支持ConfigurationProperties方式,看一个简单的示例。
1 @ConfigurationProperties(prefix = "org.dragonfei.demo") 2 public class DemoProperties { 3 private String name; 4 private String password; 5 private String test; 6 7 public String getName() { 8 return name; 9 } 10 11 public void setName(String name) { 12 this.name = name; 13 } 14 15 public String getPassword() { 16 return password; 17 } 18 19 public void setPassword(String password) { 20 this.password = password; 21 } 22 23 public String getTest() { 24 return test; 25 } 26 27 public void setTest(String test) { 28 this.test = test; 29 } 30 31 @Override 32 public String toString() { 33 return "DemoProperties{" + 34 "name='" + name + '\'' + 35 ", password='" + password + '\'' + 36 ", test='" + test + '\'' + 37 '}'; 38 } 39 }
定义Properties类
1 org.dragonfei.demo.name=dragonfei 2 org.dragonfei.demo.password=password 3 org.dragonfei.demo.test=test
添加配置
1 @Configuration 2 @EnableConfigurationProperties({DemoProperties.class}) 3 public class DemoConfiguration { 4 }
注入Properties
1 @RunWith(SpringJUnit4ClassRunner.class) 2 @SpringApplicationConfiguration(classes = DemoConfiguration.class) 3 @EnableAutoConfiguration 4 public class DemoPropertiesTest { 5 6 @Autowired 7 private DemoProperties properties; 8 @Test 9 public void testProperties(){ 10 System.out.println(properties.toString()); 11 } 12 }
简单单元测试
1 DemoProperties{name='dragonfei', password='password', test='test'}
运行单元测试结果
DemoProperties神奇的注入到Spring容器中了。有没有跟我一样很兴奋,这样的 一大好处,将配置文件的属性以类的形式展现,在需要使用的时候只需要,autowire需要的类就可以了,避免大片重复的的${a.b.c}
2.Properties属性自动装配实现
DemoProperties这么神奇注入到容器中,天下没有什么是莫名奇妙的,引出了两个关键问题:
- DemoProperties是怎样注入到容器中?
- DemoProperties中的各个属性是怎么被赋值的呢?
要回答上面的问题,必须对@Configuration如何注入bean做一个简单的回顾:
- 在解析@Congiguraion的时候,会调用@Import中引入的类
- 如果@Import中是ImportBeanDefinitionegistar的子类,会直接调用registerBeanDefinitions
- 如果@Import中是ImportSelector类型,会调用selectImports()返回的bean的registerBeanDefinitions方法。
- registerBeanDefinitions方法会向BeanFactory中添加新的bean。
回到正题。打开EnableConfigurationProperties
1 @Target(ElementType.TYPE) 2 @Retention(RetentionPolicy.RUNTIME) 3 @Documented 4 @Import(EnableConfigurationPropertiesImportSelector.class) 5 public @interface EnableConfigurationProperties { 6 7 /** 8 * Convenient way to quickly register {@link ConfigurationProperties} annotated beans 9 * with Spring. Standard Spring Beans will also be scanned regardless of this value. 10 * @return {@link ConfigurationProperties} annotated beans to register 11 */ 12 Class<?>[] value() default {}; 13 14 }
View Code
注意@Imoport里面的类
1 public String[] selectImports(AnnotationMetadata metadata) { 2 MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes( 3 EnableConfigurationProperties.class.getName(), false); 4 Object[] type = attributes == null ? null 5 : (Object[]) attributes.getFirst("value"); 6 if (type == null || type.length == 0) { 7 return new String[] { 8 ConfigurationPropertiesBindingPostProcessorRegistrar.class 9 .getName() }; 10 } 11 return new String[] { ConfigurationPropertiesBeanRegistrar.class.getName(), 12 ConfigurationPropertiesBindingPostProcessorRegistrar.class.getName() }; 13 }
View Code
然后,会调用ConfigurationPropertiesBeanRegistar和ConfigurationPropertiesBindingPostProcessorRegistar的registerBeanDefinitions方法,前者是为了注入配置properties类,后者为属性绑定值
1 @Override 2 public void registerBeanDefinitions(AnnotationMetadata metadata, 3 BeanDefinitionRegistry registry) { 4 MultiValueMap<String, Object> attributes = metadata 5 .getAllAnnotationAttributes( 6 EnableConfigurationProperties.class.getName(), false); 7 List<Class<?>> types = collectClasses(attributes.get("value")); 8 for (Class<?> type : types) { 9 String prefix = extractPrefix(type); 10 String name = (StringUtils.hasText(prefix) ? prefix + "-" + type.getName() 11 : type.getName()); 12 if (!registry.containsBeanDefinition(name)) { 13 registerBeanDefinition(registry, type, name); 14 } 15 } 16 }
ConfigurationPropertiesBeanRegistar之registerBeanDefinitions
1 public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, 2 BeanDefinitionRegistry registry) { 3 if (!registry.containsBeanDefinition(BINDER_BEAN_NAME)) { 4 BeanDefinitionBuilder meta = BeanDefinitionBuilder 5 .genericBeanDefinition(ConfigurationBeanFactoryMetaData.class); 6 BeanDefinitionBuilder bean = BeanDefinitionBuilder.genericBeanDefinition( 7 ConfigurationPropertiesBindingPostProcessor.class); 8 bean.addPropertyReference("beanMetaDataStore", METADATA_BEAN_NAME); 9 registry.registerBeanDefinition(BINDER_BEAN_NAME, bean.getBeanDefinition()); 10 registry.registerBeanDefinition(METADATA_BEAN_NAME, meta.getBeanDefinition()); 11 } 12 }
ConfigurationPropertiesBindingPostProcessorRegistar之registerBeanDefinition
注意这里注入了ConfigurationPropertiesBindingPostProcessor,这才是属性赋值的关键。查看类图
注意到ConfigurationPropertiesBindingPostProcessor继承自BeanPostProcessor,他会在bean初始化前后调用before和after后置处理,这里,在Properties属性初始化完成后,会对绑定属性,
1 private void postProcessBeforeInitialization(Object bean, String beanName, 2 ConfigurationProperties annotation) { 3 Object target = bean; 4 PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory<Object>( 5 target); 6 if (annotation != null && annotation.locations().length != 0) { 7 factory.setPropertySources( 8 loadPropertySources(annotation.locations(), annotation.merge())); 9 } 10 else { 11 factory.setPropertySources(this.propertySources); 12 } 13 factory.setValidator(determineValidator(bean)); 14 // If no explicit conversion service is provided we add one so that (at least) 15 // comma-separated arrays of convertibles can be bound automatically 16 factory.setConversionService(this.conversionService == null 17 ? getDefaultConversionService() : this.conversionService); 18 if (annotation != null) { 19 factory.setIgnoreInvalidFields(annotation.ignoreInvalidFields()); 20 factory.setIgnoreUnknownFields(annotation.ignoreUnknownFields()); 21 factory.setExceptionIfInvalid(annotation.exceptionIfInvalid()); 22 factory.setIgnoreNestedProperties(annotation.ignoreNestedProperties()); 23 if (StringUtils.hasLength(annotation.prefix())) { 24 factory.setTargetName(annotation.prefix()); 25 } 26 } 27 try { 28 factory.bindPropertiesToTarget(); 29 } 30 catch (Exception ex) { 31 String targetClass = ClassUtils.getShortName(target.getClass()); 32 throw new BeanCreationException(beanName, "Could not bind properties to " 33 + targetClass + " (" + getAnnotationDetails(annotation) + ")", ex); 34 } 35 }
绑定属性
至于真实的数据绑定,会从propertySources中获取,敬请期待....Spring 的数据绑定,这简单提一下关键的地方:
1 Set<String> names = getNames(relaxedTargetNames); 2 PropertyValues propertyValues = getPropertyValues(names, relaxedTargetNames);
View Code
请注意getNames,是获取prefix+属性构成的key值,prefix_property和prefix.property都会获取到
1 private Set<String> getNames(Iterable<String> prefixes) { 2 Set<String> names = new LinkedHashSet<String>(); 3 if (this.target != null) { 4 PropertyDescriptor[] descriptors = BeanUtils 5 .getPropertyDescriptors(this.target.getClass()); 6 for (PropertyDescriptor descriptor : descriptors) { 7 String name = descriptor.getName(); 8 if (!name.equals("class")) { 9 RelaxedNames relaxedNames = RelaxedNames.forCamelCase(name); 10 if (prefixes == null) { 11 for (String relaxedName : relaxedNames) { 12 names.add(relaxedName); 13 } 14 } 15 else { 16 for (String prefix : prefixes) { 17 for (String relaxedName : relaxedNames) { 18 names.add(prefix + "." + relaxedName); 19 names.add(prefix + "_" + relaxedName); 20 } 21 } 22 } 23 } 24 } 25 } 26 return names; 27 }
View Code
getPropertyValues会获取到满足上述条件的propertyValues,最后调用spring框架提供数据绑定策略进行数据绑定。
转载于:https://www.cnblogs.com/dragonfei/p/5906474.html
Spring 配置解析之Properties相关推荐
- Spring Boot:(六)默认日志logback配置解析
Spring Boot:(六)默认日志logback配置解析 前言 今天来介绍下Spring Boot如何配置日志logback,我刚学习的时候,是带着下面几个问题来查资料的,你呢 如何引入日志? 日 ...
- Spring多资源文件properties的配置
Spring简化了加载资源文件的配置,可以通过<context:property-placeholder去加载,这个元素的写法如下: <context:property-placehold ...
- spring配置中加载properties文件方法
首先,遇到一个问题,spring配置中加载properties文件配置如下: <context:property-placeholder ignore-unresolvable="tr ...
- spring.profiles.active配置解析、
1.在配置springcloud 时候.不了解spring.profiles.active 有什么作用.看看文档去了只有. > 查看官方文档: 2.1 Environment Repositor ...
- SpringBoot默认日志logback配置解析
SpringBoot默认日志logback配置解析 前言 今天来介绍下Spring Boot如何配置日志logback,我刚学习的时候,是带着下面几个问题来查资料的,你呢 如何引入日志? 日志输出格式 ...
- Spring bean解析 - refresh
文章目录 refresh prepareRefresh 属性校验 BeanFactory创建 BeanFactory接口 BeanFactory定制 Bean加载 EntityResolver Bea ...
- MyBatis02:CRUD操作和配置解析
MyBatis02:CRUD操作和配置解析 CRUD select 根据id查询用户 接口方法 public interface UserMapper {//查询所有用户List<User> ...
- 【SpringBoot】最新版2019Spring Boot配置解析,源码解析(速成SpringBoot)——学习笔记版【2】
SpringBoot配置文件 文章目录 SpringBoot配置文件 四.配置文件 1.简介 2.YAML用法 2.1 简介 2.2语法 3.为属性注入值 3.1使用.yml配置文件 3.1编写.ym ...
- Spring配置笔记
##Spring 的简述 1. XML配置 在Spring1.x版本,使用Spring开发全部都是XML配置的Bean,随着项目的扩大,我们经常需要XML文件分别放在不同的配置文件中,需要频繁的将类和 ...
最新文章
- 二维数组练习--矩阵的加法和乘法
- doc如何装oracle,在Windows7下安装Oracle.doc
- Java jvisualvm简要说明
- LightSwitch中的权限
- 开发板实现645协议C语言,迅为-imx6ull开发板之C语言实现LED例程
- 菜鸟要做架构师——java性能优化之for循环
- 蓝桥杯 AGLO-152 算法训练 8-2求完数
- 业内对楼市回暖时间几成共识:尚需一年
- android shell强制删除文件夹_手机文件夹都是英文,看不懂、又不敢删?教你如何辨别、释放内存...
- java jdom2_JDOM 生成和解析XML(二)
- sklearn.metrics.accuracy_score/precision_score/recall_score、micro/macro/weighted(准确率、召回率)
- maven打包jar包到本地仓库
- ArcGIS的运行许可文件ecp如何打开?
- 2021-2027全球与中国USB智能电源板市场现状及未来发展趋势
- pdcch加扰_一种基站/终端及其PDCCH加扰/解扰的方法和装置_2014104470078_权利要求书_专利查询_专利网_钻瓜专利网...
- 02—测试用例内容包含、测试用例的设计点
- android 发qq,腾讯发布QQ轻聊版 for Android V3.4.3版
- 网易有道Redis云原生实战
- vue 存取、设置、清除cookie
- iOS应用下集成携程api(酒店和飞机票)