Value注解支持对象类型ConfigurationProperties功能

Roselani ·
更新时间:2024-11-01
· 1109 次阅读

目录

真实业务场景

解决方案一

解决方案二

真实业务场景

(不希望配置类注册为Bean 或 不希望声明@ConfigurationProperties)

假设某一个jar包内封装了DataSourceProperties

@Configuration @ConfigurationProperties( prefix = "my.datasource" ) @Data public class DataSourceProperties { private List<String> suffix; private List<DataSourceDetailProperties> db; }

在jar包的Configuration中,某个@Bean的构造过程中引用了这个DataSourceProperties

public JdbcTemplate buildJdbcTemplate(DataSourceProperties dataSourceProperties) { }

在某个业务场景中,同时存在两个DataSourceProperties 会造成一个问题,注入的时候会提示有多个候选的bean 但是没法去修改Jar包中的内容

自己重复写一个DataSourceProperties 不是很优雅

这时候引出了一个需求,DataSourceProperties不希望注册为Bean,但是能够从配置文件读取构建对象

解决方案一

使用org.springframework.boot.context.properties.bind.Binder 从配置文件构建配置对象

@Bean public JdbcTemplate buildJdbcTemplate(Environment environment) { Binder binder = Binder.get(environment); DataSourceProperties properties1 = binder.bind("my.datasource1", Bindable.of(DataSourceProperties.class)).get(), properties2 = binder.bind("my.datasource2", Bindable.of(DataSourceProperties.class)).get(); }

binder.bind("xxx", Bindable.of(type)).get() 似乎是重复的编码方式?

解决方案二

使@Value注解能够支持自动调用这段代码 binder.bind("xxx", Bindable.of(type)).get() 例如

@Bean public JdbcTemplate buildJdbcTemplate(@Value("my.datasource1") DataSourceProperties properties1, @Value("my.datasource2") DataSourceProperties properties2) { }

org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency 最后会交由converter处理

Class<?> type = descriptor.getDependencyType(); Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor); if (value != null) { if (value instanceof String) { String strVal = resolveEmbeddedValue((String) value); BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null); value = evaluateBeanDefinitionString(strVal, bd); } TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); try { return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor()); } catch (UnsupportedOperationException ex) { // A custom TypeConverter which does not support TypeDescriptor resolution... return (descriptor.getField() != null ? converter.convertIfNecessary(value, type, descriptor.getField()) : converter.convertIfNecessary(value, type, descriptor.getMethodParameter())); } }

项目启动时,添加String to Object的转换器,支持@Value 并且 "bind:"开头(防止影响@Value原有功能)

package com.nuonuo.accounting.guiding.support.spring; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.bind.Bindable; import org.springframework.boot.context.properties.bind.Binder; import org.springframework.boot.convert.ApplicationConversionService; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.converter.ConditionalGenericConverter; import java.util.Set; import static java.util.Collections.singleton; /** * @author uhfun */ public class ValuePropertiesBindableAnnotationSupport implements ApplicationContextInitializer<ConfigurableApplicationContext> { private static final String PREFIX = "bind:"; @Override public void initialize(ConfigurableApplicationContext context) { Binder binder = Binder.get(context.getEnvironment()); ((ApplicationConversionService) context.getBeanFactory().getConversionService()).addConverter(new ConditionalGenericConverter() { @Override public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { Value value = targetType.getAnnotation(Value.class); return value != null && value.value().startsWith(PREFIX); } @Override public Set<ConvertiblePair> getConvertibleTypes() { return singleton(new ConvertiblePair(String.class, Object.class)); } @Override public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { Value value = targetType.getAnnotation(Value.class); Class<?> type = targetType.getType(); assert value != null; return binder.bind(value.value().replace(PREFIX, ""), Bindable.of(type)).get(); } }); } }

转换后代码执行 binder.bind(value.value().replace(PREFIX, ""), Bindable.of(type)).get(); 目的就达成了

META-INF/spring.factories中添加注册的Bean

# ApplicationContextInitializer org.springframework.context.ApplicationContextInitializer=\ com.nuonuo.accounting.guiding.support.spring.ValuePropertiesBindableAnnotationSupport,\

最终效果

@Bean public JdbcTemplate buildJdbcTemplate(@Value("bind:my.datasource1") DataSourceProperties properties1, @Value("bind:my.datasource2") DataSourceProperties properties2) { }

以上就是Value注解支持对象类型ConfigurationProperties功能的详细内容,更多关于Value支持对象类型的资料请关注软件开发网其它相关文章!



value 对象

需要 登录 后方可回复, 如果你还没有账号请 注册新账号
相关文章