SpringBoot 实现原理之 ConfigurationProperties

大家都知道 ConfigurationProperties 注解是用来注入配置类属性文件的,被 ConfigurationProperties 标注 bean 在初始化的时候 Spring 容器会将 bean 中的属性(配置文件中有的)进行填充。那它具体是如何实现的呢?

属性配置类注册

当我们需要 Spring 为我们自动填充属性文件时需要使用 EnableConfigurationProperties 进行指定,例如:ServletWebServerFactoryAutoConfiguration 的代码如下:

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(ServerProperties.class)
public class ServletWebServerFactoryAutoConfiguration {
}

当 Spring 容器加载 EnableConfigurationProperties 注解时会导入 EnableConfigurationPropertiesRegistrar 类

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EnableConfigurationPropertiesRegistrar.class)
public @interface EnableConfigurationProperties {

	/**
	 * The bean name of the configuration properties validator.
	 * @since 2.2.0
	 */
	String VALIDATOR_BEAN_NAME = "configurationPropertiesValidator";

	/**
	 * Convenient way to quickly register
	 * {@link ConfigurationProperties @ConfigurationProperties} annotated beans with
	 * Spring. Standard Spring Beans will also be scanned regardless of this value.
	 * @return {@code @ConfigurationProperties} annotated beans to register
	 */
	Class<?>[] value() default {};

}

EnableConfigurationPropertiesRegistrar 是 ImportBeanDefinitionRegistrar 的实例,Spring 初始化的时候会调用 registerBeanDefinitions 方法将 EnableConfigurationProperties 注解标注的 bean 添加到 spring 容器中。

@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
    // 用来将 ConfigurationPropertiesBindingPostProcessor 注册到 spring 容器中
	registerInfrastructureBeans(registry);	
	registerMethodValidationExcludeFilter(registry);
	ConfigurationPropertiesBeanRegistrar beanRegistrar = new ConfigurationPropertiesBeanRegistrar(registry);
	getTypes(metadata).forEach(beanRegistrar::register);
}

private Set<Class<?>> getTypes(AnnotationMetadata metadata) {
	return metadata.getAnnotations().stream(EnableConfigurationProperties.class)
			.flatMap((annotation) -> Arrays.stream(annotation.getClassArray(MergedAnnotation.VALUE)))
			.filter((type) -> void.class != type).collect(Collectors.toSet());
}

static void registerInfrastructureBeans(BeanDefinitionRegistry registry) {
	ConfigurationPropertiesBindingPostProcessor.register(registry);
	BoundConfigurationProperties.register(registry);
}

public static void register(BeanDefinitionRegistry registry) {
	Assert.notNull(registry, "Registry must not be null");
	if (!registry.containsBeanDefinition(BEAN_NAME)) {
		BeanDefinition definition = BeanDefinitionBuilder
				.rootBeanDefinition(ConfigurationPropertiesBindingPostProcessor.class).getBeanDefinition();
		definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		registry.registerBeanDefinition(BEAN_NAME, definition);
	}
	ConfigurationPropertiesBinder.register(registry);
}

属性配置类属性填充

SpringBoot 初始化的时候会调用 ConfigurationPropertiesBindingPostProcessor 类(实现了 BeanPostProcessor 接口)中的 postProcessBeforeInitialization 方法进行属性的填充

@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		bind(ConfigurationPropertiesBean.get(this.applicationContext, bean, beanName));
		return bean;
	}

	private void bind(ConfigurationPropertiesBean bean) {
		if (bean == null || hasBoundValueObject(bean.getName())) {
			return;
		}
		Assert.state(bean.getBindMethod() == BindMethod.JAVA_BEAN, "Cannot bind @ConfigurationProperties for bean '"
				+ bean.getName() + "'. Ensure that @ConstructorBinding has not been applied to regular bean");
		try {
			this.binder.bind(bean);
		}
		catch (Exception ex) {
			throw new ConfigurationPropertiesBindException(bean, ex);
		}
	}

至此,ConfigurationProperties 实现原理讲解完毕。

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值