SpringBoot ConfigurationProperties
- Author: HuiFer
源码阅读仓库: SourceHot-spring-boot
本文主要对
org.springframework.boot.context.properties.ConfigurationProperties进行分析
ConfigurationProperties
- 顶部注释
* @see ConfigurationPropertiesScan* @see ConstructorBinding* @see ConfigurationPropertiesBindingPostProcessor* @see EnableConfigurationProperties
看到ConfigurationPropertiesScan 去看看这个
ConfigurationPropertiesScan
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Import(ConfigurationPropertiesScanRegistrar.class)@EnableConfigurationPropertiespublic @interface ConfigurationPropertiesScan {}
- 熟悉的Import注解
ConfigurationPropertiesScanRegistrar

- debug 没有抓到后续补充
EnableConfigurationProperties
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Import(EnableConfigurationPropertiesRegistrar.class)public @interface EnableConfigurationProperties {}
EnableConfigurationPropertiesRegistrar
该类会读取spring.factories
中
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\这样的org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfigurationorg.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration$DispatcherServletConfigurationorg.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration$DispatcherServletRegistrationConfigurationorg.springframework.boot.autoconfigure.task.TaskExecutionAutoConfigurationorg.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfigurationorg.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapterorg.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfigurationorg.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$Jackson2ObjectMapperBuilderCustomizerConfigurationorg.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration$StringHttpMessageConverterConfigurationorg.springframework.boot.autoconfigure.info.ProjectInfoAutoConfigurationorg.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfigurationorg.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfigurationorg.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfigurationorg.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfigurationorg.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration
@Overridepublic void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {// 注册beanregisterInfrastructureBeans(registry);// 配置属性Bean注册器ConfigurationPropertiesBeanRegistrar beanRegistrar = new ConfigurationPropertiesBeanRegistrar(registry);// 循环注册getTypes(metadata).forEach(beanRegistrar::register);}
registerInfrastructureBeans
static void registerInfrastructureBeans(BeanDefinitionRegistry registry) {// 属性绑定后置处理器ConfigurationPropertiesBindingPostProcessor.register(registry);// 属性校验器ConfigurationPropertiesBeanDefinitionValidator.register(registry);ConfigurationBeanFactoryMetadata.register(registry);}
- 此处操作逻辑基本相同,是否存在这个 beanName 存在直接注册,不存在补充
ConfigurationPropertiesBindingPostProcessor.register(registry)
public static void register(BeanDefinitionRegistry registry) {Assert.notNull(registry, "Registry must not be null");// 是否存在if (!registry.containsBeanDefinition(BEAN_NAME)) {GenericBeanDefinition definition = new GenericBeanDefinition();definition.setBeanClass(ConfigurationPropertiesBindingPostProcessor.class);definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);registry.registerBeanDefinition(BEAN_NAME, definition);}ConfigurationPropertiesBinder.register(registry);}
ConfigurationPropertiesBeanDefinitionValidator.register(registry)
static void register(BeanDefinitionRegistry registry) {Assert.notNull(registry, "Registry must not be null");if (!registry.containsBeanDefinition(BEAN_NAME)) {GenericBeanDefinition definition = new GenericBeanDefinition();definition.setBeanClass(ConfigurationPropertiesBeanDefinitionValidator.class);definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);registry.registerBeanDefinition(BEAN_NAME, definition);}ConfigurationPropertiesBinder.register(registry);}
getTypes(metadata).forEach(beanRegistrar::register)
- 先看输入参数 metadata

- getTypes 结果

源码开始,先找出刚才的对象
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration@Configuration(proxyBeanMethods = false)@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)@ConditionalOnClass(ServletRequest.class)@ConditionalOnWebApplication(type = Type.SERVLET)@EnableConfigurationProperties(ServerProperties.class)@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,ServletWebServerFactoryConfiguration.EmbeddedJetty.class,ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })public class ServletWebServerFactoryAutoConfiguration {}
/*** 找出 {@link EnableConfigurationProperties} 注解标记的中的属性值,并且返回值不是void* @param metadata* @return*/private Set<Class<?>> getTypes(AnnotationMetadata metadata) {returnmetadata.getAnnotations().stream(EnableConfigurationProperties.class).flatMap((annotation) -> Arrays.stream(annotation.getClassArray(MergedAnnotation.VALUE))).filter((type) -> void.class != type).collect(Collectors.toSet());}
- 这里我们可以直接知道返回的是
@EnableConfigurationProperties(ServerProperties.class)的数据值:ServerProperties.class
循环注册
void register(Class<?> type) {MergedAnnotation<ConfigurationProperties> annotation = MergedAnnotations.from(type, SearchStrategy.TYPE_HIERARCHY).get(ConfigurationProperties.class);register(type, annotation);}
ConfigurationPropertiesBindingPostProcessor

postProcessBeforeInitialization
@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {// 绑定bind(ConfigurationPropertiesBean.get(this.applicationContext, bean, beanName));return bean;}
get
public static ConfigurationPropertiesBean get(ApplicationContext applicationContext, Object bean, String beanName) {// 寻找工厂方法Method factoryMethod = findFactoryMethod(applicationContext, beanName);// 创建 ConfigurationPropertiesBeanreturn create(beanName, bean, bean.getClass(), factoryMethod);}
private static Method findFactoryMethod(ConfigurableListableBeanFactory beanFactory, String beanName) {// 判断是否存在这个beanNameif (beanFactory.containsBeanDefinition(beanName)) {// 获取bean定义BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(beanName);// 类型判断if (beanDefinition instanceof RootBeanDefinition) {// 解析方法Method resolvedFactoryMethod = ((RootBeanDefinition) beanDefinition).getResolvedFactoryMethod();if (resolvedFactoryMethod != null) {return resolvedFactoryMethod;}}return findFactoryMethodUsingReflection(beanFactory, beanDefinition);}return null;}
private static Method findFactoryMethodUsingReflection(ConfigurableListableBeanFactory beanFactory,BeanDefinition beanDefinition) {// 工厂方法String factoryMethodName = beanDefinition.getFactoryMethodName();// 工厂beanString factoryBeanName = beanDefinition.getFactoryBeanName();if (factoryMethodName == null || factoryBeanName == null) {return null;}// 转换对象Class<?> factoryType = beanFactory.getType(factoryBeanName);if (factoryType.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {factoryType = factoryType.getSuperclass();}AtomicReference<Method> factoryMethod = new AtomicReference<>();ReflectionUtils.doWithMethods(factoryType, (method) -> {// 判断是否是需要的方法if (method.getName().equals(factoryMethodName)) {// 设置方法factoryMethod.set(method);}});// 返回方法return factoryMethod.get();}
create
org.springframework.boot.context.properties.ConfigurationPropertiesBean#create
private static ConfigurationPropertiesBean create(String name, Object instance, Class<?> type, Method factory) {// 找注解ConfigurationProperties annotation = findAnnotation(instance, type, factory, ConfigurationProperties.class);if (annotation == null) {return null;}// 找注解Validated validated = findAnnotation(instance, type, factory, Validated.class);// 注解列表Annotation[] annotations = (validated != null) ? new Annotation[] { annotation, validated }: new Annotation[] { annotation };// 类型解析ResolvableType bindType = (factory != null) ? ResolvableType.forMethodReturnType(factory): ResolvableType.forClass(type);// 绑定结果对象Bindable<Object> bindTarget = Bindable.of(bindType).withAnnotations(annotations);if (instance != null) {bindTarget = bindTarget.withExistingValue(instance);}return new ConfigurationPropertiesBean(name, instance, annotation, bindTarget);}
第一个需要做的类:
org.springframework.boot.autoconfigure.web.ServerPropertiesannotation

bindType

- 返回对象

- 此时数据还没有进去
bind
- 数据绑定
直接看结果

- 上述配置和我在配置文件中写的配置一致
server:port: 9999
- 具体方法:
org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor#bind
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);}}
BindResult<?> bind(ConfigurationPropertiesBean propertiesBean) {// 最后的结果Bindable<?> target = propertiesBean.asBindTarget();// 注解获取ConfigurationProperties annotation = propertiesBean.getAnnotation();// 获取处理器BindHandler bindHandler = getBindHandler(target, annotation);//return getBinder().bind(annotation.prefix(), target, bindHandler);}

findProperty
private ConfigurationProperty findProperty(ConfigurationPropertyName name, Context context) {if (name.isEmpty()) {return null;}for (ConfigurationPropertySource source : context.getSources()) {// 获取具体的一个属性值ConfigurationProperty property = source.getConfigurationProperty(name);if (property != null) {return property;}}return null;}
org.springframework.boot.context.properties.source.SpringConfigurationPropertySource#getConfigurationProperty@Overridepublic ConfigurationProperty getConfigurationProperty(ConfigurationPropertyName name) {PropertyMapping[] mappings = getMapper().map(name);return find(mappings, name);}
protected final ConfigurationProperty find(PropertyMapping[] mappings, ConfigurationPropertyName name) {for (PropertyMapping candidate : mappings) {if (candidate.isApplicable(name)) {ConfigurationProperty result = find(candidate);if (result != null) {return result;}}}return null;}
private ConfigurationProperty find(PropertyMapping mapping) {// 需要读取的配置信息的keyString propertySourceName = mapping.getPropertySourceName();// 信息的valueObject value = getPropertySource().getProperty(propertySourceName);if (value == null) {return null;}// 创建对象ConfigurationPropertyName configurationPropertyName = mapping.getConfigurationPropertyName();Origin origin = PropertySourceOrigin.get(this.propertySource, propertySourceName);// 包装返回return ConfigurationProperty.of(configurationPropertyName, value, origin);}



getBindHandler
private <T> BindHandler getBindHandler(Bindable<T> target, ConfigurationProperties annotation) {// 获取校验接口列表List<Validator> validators = getValidators(target);// 处理器BindHandler handler = new IgnoreTopLevelConverterNotFoundBindHandler();if (annotation.ignoreInvalidFields()) {// 忽略错误的绑定处理器handler = new IgnoreErrorsBindHandler(handler);}if (!annotation.ignoreUnknownFields()) {UnboundElementsSourceFilter filter = new UnboundElementsSourceFilter();// 未绑定元素处理器handler = new NoUnboundElementsBindHandler(handler, filter);}if (!validators.isEmpty()) {// 校验绑定处理器handler = new ValidationBindHandler(handler, validators.toArray(new Validator[0]));}for (ConfigurationPropertiesBindHandlerAdvisor advisor : getBindHandlerAdvisors()) {// handlerhandler = advisor.apply(handler);}return handler;}
- 最终获取得到的处理器

- 最后的 bind
private <T> Object bindObject(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler,Context context, boolean allowRecursiveBinding) {// 获取属性ConfigurationProperty property = findProperty(name, context);if (property == null && containsNoDescendantOf(context.getSources(), name) && context.depth != 0) {return null;}AggregateBinder<?> aggregateBinder = getAggregateBinder(target, context);if (aggregateBinder != null) {return bindAggregate(name, target, handler, context, aggregateBinder);}if (property != null) {try {return bindProperty(target, context, property);}catch (ConverterNotFoundException ex) {// We might still be able to bind it using the recursive bindersObject instance = bindDataObject(name, target, handler, context, allowRecursiveBinding);if (instance != null) {return instance;}throw ex;}}return bindDataObject(name, target, handler, context, allowRecursiveBinding);}

配置信息到此绑定成功,关于如何处理集合相关的配置请各位读者自行学习
