1. 概述
本文我们来分享 @ConfigurationProperties
注解,如何将配置文件自动设置到被注解的类。代码如下:
// ConfigurationProperties.java |
@ConfigurationProperties
注解有两种使用方法,可见 《关与 @EnableConfigurationProperties 注解》 文章。总结来说:
- 第一种,
@Component
+@ConfigurationProperties
。 - 第二种,
@EnableConfigurationProperties
+ConfigurationProperties
。
实际情况下,更多的是使用第一种。当然,第二种的 @EnableConfigurationProperties
的效果,也是将指定的类,实现和 @Component
被注解的类是一样的,创建成 Bean 对象。
这样,@ConfigurationProperties
就可以将配置文件自动设置到该 Bean 对象咧。
2. @EnableConfigurationProperties
org.springframework.boot.context.properties.@EnableConfigurationProperties
注解,可以将指定带有 @ConfigurationProperties
的类,注册成 BeanDefinition ,从而创建成 Bean 对象。代码如下:
// EnableConfigurationProperties.java |
- 从
@Import
注解上,可以看到使用 EnableConfigurationPropertiesImportSelector 处理。详细的解析,见 「2.2 EnableConfigurationPropertiesImportSelector」 。
2.1 ConfigurationPropertiesAutoConfiguration
默认情况下,@EnableConfigurationProperties
会通过 org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration
类,进行开启。代码如下:
// ConfigurationPropertiesAutoConfiguration.java |
- 看,看看,看看看,
<X>
哟~
2.2 EnableConfigurationPropertiesImportSelector
org.springframework.boot.context.properties.EnableConfigurationPropertiesImportSelector
,实现 ImportSelector 接口,处理 @EnableConfigurationProperties
注解。代码如下:
// EnableConfigurationPropertiesImportSelector.java |
- 返回的
IMPORTS
的是两个 ImportBeanDefinitionRegistrar 实现类。分别是:- ConfigurationPropertiesBeanRegistrar ,在 「2.3 ConfigurationPropertiesBeanRegistrar」 中详细解析。
- ConfigurationPropertiesBindingPostProcessorRegistrar ,在 「2.4 ConfigurationPropertiesBindingPostProcessorRegistrar」 中详细解析。
2.3 ConfigurationPropertiesBeanRegistrar
ConfigurationPropertiesBeanRegistrar ,是 EnableConfigurationPropertiesImportSelector 的内部静态类,实现 ImportBeanDefinitionRegistrar 接口,将 @EnableConfigurationProperties
注解指定的类,逐个注册成对应的 BeanDefinition 对象。代码如下:
// EnableConfigurationPropertiesImportSelector#ConfigurationPropertiesBeanRegistrar.java |
-
<1>
处,调用#getTypes(AnnotationMetadata metadata)
方法,获得@EnableConfigurationProperties
注解指定的类的数组。代码如下:// EnableConfigurationPropertiesImportSelector#ConfigurationPropertiesBeanRegistrar.java
private List<Class<?>> getTypes(AnnotationMetadata metadata) {
// 获得 @EnableConfigurationProperties 注解
MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(EnableConfigurationProperties.class.getName(), false);
// 获得 value 属性
return collectClasses((attributes != null) ? attributes.get("value")
: Collections.emptyList());
}
private List<Class<?>> collectClasses(List<?> values) {
return values.stream().flatMap((value) -> Arrays.stream((Object[]) value))
.map((o) -> (Class<?>) o).filter((type) -> void.class != type)
.collect(Collectors.toList());
}- ~
-
<2>
处,遍历,逐个调用#register(BeanDefinitionRegistry registry, ConfigurableListableBeanFactory beanFactory, Class<?> type)
方法,注册每个类对应的 BeanDefinition 对象。代码如下:// EnableConfigurationPropertiesImportSelector#ConfigurationPropertiesBeanRegistrar.java
private void register(BeanDefinitionRegistry registry, ConfigurableListableBeanFactory beanFactory, Class<?> type) {
// <2.1> 通过 @ConfigurationProperties 注解,获得最后要生成的 BeanDefinition 的名字。格式为 prefix-类全名 or 类全名
String name = getName(type);
// <2.2> 判断是否已经有该名字的 BeanDefinition 的名字。没有,才进行注册
if (!containsBeanDefinition(beanFactory, name)) {
registerBeanDefinition(registry, name, type); // <2.3>
}
}-
<2.1>
处,调用#getName(Class<?> type)
方法,通过@ConfigurationProperties
注解,获得最后要生成的 BeanDefinition 的名字。代码如下:// EnableConfigurationPropertiesImportSelector#ConfigurationPropertiesBeanRegistrar.java
private String getName(Class<?> type) {
ConfigurationProperties annotation = AnnotationUtils.findAnnotation(type, ConfigurationProperties.class);
String prefix = (annotation != null) ? annotation.prefix() : "";
return (StringUtils.hasText(prefix) ? prefix + "-" + type.getName() : type.getName());
}- 格式为
prefix-
类全名 or 类全名。
- 格式为
-
<2.2>
处,调用#containsBeanDefinition(ConfigurableListableBeanFactory beanFactory, String name)
方法,判断是否已经有该名字的 BeanDefinition 的名字。代码如下:// EnableConfigurationPropertiesImportSelector#ConfigurationPropertiesBeanRegistrar.java
private boolean containsBeanDefinition(ConfigurableListableBeanFactory beanFactory, String name) {
// 判断是否存在 BeanDefinition 。如果有,则返回 true
if (beanFactory.containsBeanDefinition(name)) {
return true;
}
// 获得父容器,判断是否存在
BeanFactory parent = beanFactory.getParentBeanFactory();
if (parent instanceof ConfigurableListableBeanFactory) {
return containsBeanDefinition((ConfigurableListableBeanFactory) parent, name);
}
// 返回 false ,说明不存在
return false;
}- 如果不存在,才执行后续的注册 BeanDefinition 逻辑。
-
<2.3>
处,调用#registerBeanDefinition(BeanDefinitionRegistry registry, String name, Class<?> type)
方法,注册 BeanDefinition 。代码如下:// EnableConfigurationPropertiesImportSelector#ConfigurationPropertiesBeanRegistrar.java
private void registerBeanDefinition(BeanDefinitionRegistry registry, String name, Class<?> type) {
// 断言,判断该类有 @ConfigurationProperties 注解
assertHasAnnotation(type);
// 创建 GenericBeanDefinition 对象
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClass(type);
// 注册到 BeanDefinitionRegistry 中
registry.registerBeanDefinition(name, definition);
}
private void assertHasAnnotation(Class<?> type) {
Assert.notNull(
AnnotationUtils.findAnnotation(type, ConfigurationProperties.class),
() -> "No " + ConfigurationProperties.class.getSimpleName()
+ " annotation found on '" + type.getName() + "'.");
}- ~
-
2.4 ConfigurationPropertiesBindingPostProcessorRegistrar
org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessorRegistrar
,实现 ImportBeanDefinitionRegistrar 接口,代码如下:
// ConfigurationPropertiesBindingPostProcessorRegistrar.java |
-
<1>
处,调用#registerConfigurationPropertiesBindingPostProcessor(BeanDefinitionRegistry registry)
方法,注册 ConfigurationPropertiesBindingPostProcessor BeanDefinition 。代码如下:// ConfigurationPropertiesBindingPostProcessorRegistrar.java
private void registerConfigurationPropertiesBindingPostProcessor(BeanDefinitionRegistry registry) {
// 创建 GenericBeanDefinition 对象
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClass(ConfigurationPropertiesBindingPostProcessor.class);
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 注册
registry.registerBeanDefinition(ConfigurationPropertiesBindingPostProcessor.BEAN_NAME, definition);
}- 关于 ConfigurationPropertiesBindingPostProcessor 类,我们在 「4. ConfigurationPropertiesBindingPostProcessor 相关」 中,详细解析。
-
<2>
处,调用#registerConfigurationBeanFactoryMetadata(BeanDefinitionRegistry registry)
方法,注册 ConfigurationBeanFactoryMetadata BeanDefinition 。代码如下:// ConfigurationPropertiesBindingPostProcessorRegistrar.java
private void registerConfigurationBeanFactoryMetadata(BeanDefinitionRegistry registry) {
// 创建 GenericBeanDefinition 对象
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClass(ConfigurationBeanFactoryMetadata.class);
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 注册
registry.registerBeanDefinition(ConfigurationBeanFactoryMetadata.BEAN_NAME, definition);
}- 关于 ConfigurationBeanFactoryMetadata 类,我们在 「3. ConfigurationBeanFactoryMetadata」 中,详细解析。
3. ConfigurationBeanFactoryMetadata
org.springframework.boot.context.properties.ConfigurationBeanFactoryMetadata
,初始化配置类创建 Bean 的每个方法的元数据。
3.1 postProcessBeanFactory
实现 #postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
方法,代码如下:
// ConfigurationBeanFactoryMetadata.java |
-
<1>
处,初始化beanFactory
属性。 -
<2>
处,遍历所有的 BeanDefinition 的名字们,初始化beansFactoryMetadata
属性。 -
<2.1>
处,获得 BeanDefinition 对象。 -
<2.2>
处,获得 BeanDefinition 的factoryMethodName
、factoryBeanName
属性。-
factoryBeanName
属性,是创建该 Bean 的工厂 Bean 的名字。 -
factoryMethodName
属性,是创建 Bean 的工厂 Bean 的方法名。 -
以如下的 Configuration 类,举个例子:
public class TestConfiguration {
public Object testObject() {
return new Object();
}
}- 每个
@Bean
注解的方法,都是一个factoryBeanName
+factoryMethodName
。 -
factoryBeanName
属性,为"testConfiguration"
。 -
factoryMethodName
属性,为"testObject"
。
- 每个
-
-
<2.3>
处,都非空的情况下,添加到beansFactoryMetadata
中。 -
FactoryMetadata 是 ConfigurationBeanFactoryMetadata 的内部静态类。代码如下:
// ConfigurationBeanFactoryMetadata#FactoryMetadata.java
private static class FactoryMetadata {
/**
* Bean 的名字
*/
private final String bean;
/**
* Bean 的方法名
*/
private final String method;
// ... 省略 setting / getting 方法
}
3.2 findFactoryMethod
#findFactoryMethod(String beanName)
方法,获得指定 Bean 的创建方法。代码如下:
// ConfigurationBeanFactoryMetadata.java |
3.3 findFactoryAnnotation
#findFactoryAnnotation(String beanName, Class<A> type)
方法,获得指定 Bean 的创建方法上的注解。代码如下:
// ConfigurationBeanFactoryMetadata.java |
3.4 getBeansWithFactoryAnnotation
#getBeansWithFactoryAnnotation(Class<A> type)
方法,获得 beansFactoryMetadata
中的每个 Bean 的方法上的指定注解。代码如下:
// ConfigurationBeanFactoryMetadata.java |
相关推荐
在Spring Boot框架中,`@ConfigurationProperties`注解是一个核心特性,它允许我们将配置属性从外部化配置文件(如application.properties或application.yml)绑定到Java对象的字段上,从而简化了属性管理。...
在Spring Boot中注解@ConfigurationProperties有三种使用场景,而通常情况下我们使用的最多的只是其中的一种场景。本篇文章带大家了解一下三种场景的使用情况。 1.2 场景一 使用@ConfigurationProperties和@...
jpa的依赖 (spring-boot-starter-data-jpa) 3.1.2.4 JavaBean对象 3.1.2.5 application.properties配置文件 3.1.2.6 配置类 3.1.2.7 测试类 3.1.3问题与解答 问题: 解答与分析: 案例实操 3.2 作用于Class类及其...
"Spring Boot 2.0 @ConfigurationProperties 使用详解" 概述 {@ConfigurationProperties} 是 Spring Boot 2.0 中的一个核心功能,用于简化外部化配置方式的使用。通过使用 {@ConfigurationProperties},可以轻松地...
在Spring Boot中,`@ConfigurationProperties` 是一个强大的特性,用于将配置文件(如application.properties或application.yml)中的键值对映射到Java对象的属性上。这使得开发者能够更方便地管理和使用配置信息,...
Spring Boot系列四 Spring @Value 属性注入使用总结一
@ConfigurationProperties是Spring Boot提供的一种强大的特性,用于将配置文件(如application.properties或application.yml)中的键值对映射到Java对象的属性上。这使得我们可以更方便地管理和使用配置信息,尤其是...
本示例“spring boot整合JPA——demo”将演示如何在Spring Boot项目中配置和使用JPA。 首先,我们需要理解Spring Boot与JPA的关系。Spring Boot是基于Spring框架的快速开发工具,它通过自动化配置减少了常规设置...
接下来,`@ConfigurationProperties`是Spring Boot提供的一个高级特性,它允许我们将配置文件(如application.properties或application.yml)中的键值对映射到一个Java类的字段上。这大大简化了处理配置的工作,使...
在Spring Boot中,`@ConfigurationProperties`是用于将配置文件中的属性绑定到Java Bean的注解,极大地简化了属性的管理,使得配置更加灵活和类型安全。以下是对`@ConfigurationProperties`的详细解析。 **1. 添加...
**Spring Boot创建与运行项目详解** Spring Boot是Java开发领域中的一个热门框架,它通过简化配置和自动装配,使得创建和运行Spring应用变得更加容易。在本篇内容中,我们将深入探讨如何利用Spring Boot来创建和...
深入学习spring boot 懂得各个标签,注解的用途和原理
在Spring Boot中测试@ConfigurationProperties 该项目显示了如何在Spring Boot中测试@ConfigurationProperties。 您可以在以下位置找到有关此内容的博客文章:
通过源码分析,开发者可以更好地理解Spring Boot的自动装配、启动流程以及如何自定义启动器。Spring Boot的自动装配原理涉及到Spring Boot的核心特性,它简化了基于Spring的应用开发,通过自动配置减少了大量的配置...
通过深入阅读和分析Spring Boot 2.7.0的源码,我们可以了解到Spring Boot是如何实现其核心特性的,以及如何利用Spring Framework进行扩展和定制。同时,这也有助于我们更好地利用Spring Boot进行微服务开发,提高...
《果子学院Spring Boot源码解析》是一套深入学习Spring Boot源码的教程,旨在帮助开发者深入了解这个流行的Java开发框架的内部工作机制。Spring Boot简化了Java应用的初始搭建以及开发过程,它集成了大量常用的第三...
《Spring源码分析——ApplicationContext》 在Java世界中,Spring框架是不可或缺的一部分,它以其强大的IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)特性,极大地...
在这个版本中,我们将深入探讨Spring Boot的核心特性、工作原理以及如何通过源码来理解其内部机制。 首先,Spring Boot的核心理念是“约定优于配置”,它通过预设许多默认配置,减少了开发者需要手动配置的繁琐工作...
Spring Boot的配置文件(application.properties或application.yml)的使用方法,以及如何通过@ConfigurationProperties将配置绑定到Java对象,也是学习的重点。 Spring Boot对于数据库的支持非常全面,包括JDBC、...
《Spring Boot实战派》源码提供了丰富的学习材料,旨在帮助开发者深入理解并...通过分析《Spring Boot实战派》源码,读者不仅可以了解上述技术点,还能学习到如何在实际项目中应用这些技术,提升开发效率和代码质量。