该文章为原创(转载请注明出处):如何使@Value注解反对相似@ConfigurationProperties的性能? - 简书 (jianshu.com)

实在业务场景(不心愿配置类注册为Bean 或 不心愿申明@ConfigurationProperties)

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

@Configuration@ConfigurationProperties(    prefix = "my.datasource")@Datapublic 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 从配置文件构建配置对象

@Beanpublic 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()
例如

@Beanpublic 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

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

最终成果

@Beanpublic JdbcTemplate buildJdbcTemplate(@Value("bind:my.datasource1") DataSourceProperties properties1,                                      @Value("bind:my.datasource2") DataSourceProperties properties2) {   }
该文章为原创(转载请注明出处):如何使@Value注解反对相似@ConfigurationProperties的性能? - 简书 (jianshu.com)