Spring Boot ConfigurationProperties注解

Spring Boot ConfigurationProperties注解能够将Propeties和加了此注解的类属性绑定。那么它是如何工作的?

构建 ConfigurationPropertiesBindingPostProcessor bean

Spring Boot中此注解相关的核心处理逻辑在ConfigurationPropertiesBindingPostProcessor类,实现了BeanPostProcessor接口,所以此类必须也要作为bean,一般按照往常Spring Boot的做法,会构造一个XxxAutoConfiguration自动配置类,但是此类的自动配置我怎么都没找到,最后发现此类的注册过程由ConfigurationPropertiesBindingPostProcessorRegistrar动态注册实现。

ConfigurationPropertiesBindingPostProcessor通过ConfigurationPropertiesBindingPostProcessorRegistrar类,将此ConfigurationPropertiesBindingPostProcessor注册到spring BeanFactory,注册代码如下

public static final String BINDER_BEAN_NAME = ConfigurationPropertiesBindingPostProcessor.class
		.getName();

private static final String METADATA_BEAN_NAME = BINDER_BEAN_NAME + ".store";

@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
		BeanDefinitionRegistry registry) {
	if (!registry.containsBeanDefinition(BINDER_BEAN_NAME)) {
		BeanDefinitionBuilder meta = BeanDefinitionBuilder
				.genericBeanDefinition(ConfigurationBeanFactoryMetaData.class);
		//获取 ConfigurationPropertiesBindingPostProcessor BeanDefinition
		BeanDefinitionBuilder bean = BeanDefinitionBuilder.genericBeanDefinition(
				ConfigurationPropertiesBindingPostProcessor.class);
		bean.addPropertyReference("beanMetaDataStore", METADATA_BEAN_NAME);
		//注册
		registry.registerBeanDefinition(BINDER_BEAN_NAME, bean.getBeanDefinition());
		registry.registerBeanDefinition(METADATA_BEAN_NAME, meta.getBeanDefinition());
	}
}

ConfigurationPropertiesBindingPostProcessor 绑定配置

由于ConfigurationPropertiesBindingPostProcessor类实现了BeanPostProcessor接口,所以所有的bean都会被ConfigurationPropertiesBindingPostProcessorpostProcessBeforeInitializationpostProcessAfterInitialization处理。其处理方式如下

@Override
public 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;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
		throws BeansException {
	return bean;
}

通过代码可以看到postProcessBeforeInitialization方法内,会对每个bean做处理。如果此beanConfigurationProperties注解,会调用postProcessBeforeInitialization(bean, beanName, annotation);

private void postProcessBeforeInitialization(Object bean, String beanName,
		ConfigurationProperties annotation) {
	Object target = bean;
	PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory<Object>(
			target);
	factory.setPropertySources(this.propertySources);
	factory.setApplicationContext(this.applicationContext);
	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 automatically
	factory.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);
	}
}

上面的代码里通过factory.bindPropertiesToTarget();方法,进行bean和配置绑定。通过追踪,会调用DataBinderdoBind方法,进行绑定

protected void doBind(MutablePropertyValues mpvs) {
	checkAllowedFields(mpvs);
	checkRequiredFields(mpvs);
	applyPropertyValues(mpvs);
}

具体细节就不在深入。在doBinder方法调用之前,会设置DataBinder对象的一些配置,比如松绑的,忽略未知字段等配置项。

总结

ConfigurationProperties注解也并没非常的神秘,其内部核心逻辑也是基于BeanPostProcessor接口,来处理每个bean,通过过滤获取标有@ConfigurationProperties注解的class,通过environment获取PropertySources,绑定属性。其中environment通过EnvironmentAware接口获取。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
@ConfigurationPropertiesSpring Boot 中的一个注解,用于将配置文件中的属性映射到 Java 对象中。通过 @ConfigurationProperties 注解,我们可以将配置文件中的属性值注入到一个被 @Component 或 @Configuration 注解的类中作为属性。 使用 @ConfigurationProperties 注解时需要指定一个前缀,该前缀与配置文件中的属性名进行匹配。然后,通过添加对应的 setter 方法,可以将属性值注入到被注解的类的实例中。 例如,假设我们有一个名为 "myapp" 的属性前缀,配置文件中有一个属性 "myapp.name",我们可以通过以下方式进行注解和映射: ```java @Component @ConfigurationProperties(prefix = "myapp") public class MyAppProperties { private String name; // Getter and Setter methods } ``` 在上述示例中,当 Spring Boot 启动时,会自动将配置文件中的 "myapp.name" 属性的值注入到 MyAppProperties 类的实例中的 name 属性。 注意,为了使 @ConfigurationProperties 生效,我们还需要在应用程序的入口处添加 @EnableConfigurationProperties 注解,并指定要扫描的类。 ```java @SpringBootApplication @EnableConfigurationProperties(MyAppProperties.class) public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } } ``` 这样,我们就可以在应用程序中使用 @Autowired 注解将 MyAppProperties 类注入到其他类中,并使用其中的属性值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值