Value注解支持對(duì)象類型ConfigurationProperties功能
真實(shí)業(yè)務(wù)場(chǎng)景
(不希望配置類注冊(cè)為Bean 或 不希望聲明@ConfigurationProperties)
假設(shè)某一個(gè)jar包內(nèi)封裝了DataSourceProperties
@Configuration
@ConfigurationProperties(
prefix = "my.datasource"
)
@Data
public class DataSourceProperties {
private List<String> suffix;
private List<DataSourceDetailProperties> db;
}
在jar包的Configuration中,某個(gè)@Bean的構(gòu)造過程中引用了這個(gè)DataSourceProperties
public JdbcTemplate buildJdbcTemplate(DataSourceProperties dataSourceProperties) {
}
在某個(gè)業(yè)務(wù)場(chǎng)景中,同時(shí)存在兩個(gè)DataSourceProperties 會(huì)造成一個(gè)問題,注入的時(shí)候會(huì)提示有多個(gè)候選的bean 但是沒法去修改Jar包中的內(nèi)容
自己重復(fù)寫一個(gè)DataSourceProperties 不是很優(yōu)雅
這時(shí)候引出了一個(gè)需求,DataSourceProperties不希望注冊(cè)為Bean,但是能夠從配置文件讀取構(gòu)建對(duì)象
解決方案一
使用org.springframework.boot.context.properties.bind.Binder 從配置文件構(gòu)建配置對(duì)象
@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() 似乎是重復(fù)的編碼方式?
解決方案二
使@Value注解能夠支持自動(dòng)調(diào)用這段代碼 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 最后會(huì)交由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()));
}
}
項(xiàng)目啟動(dòng)時(shí),添加String to Object的轉(zhuǎn)換器,支持@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();
}
});
}
}
轉(zhuǎn)換后代碼執(zhí)行 binder.bind(value.value().replace(PREFIX, ""), Bindable.of(type)).get(); 目的就達(dá)成了
在META-INF/spring.factories中添加注冊(cè)的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注解支持對(duì)象類型ConfigurationProperties功能的詳細(xì)內(nèi)容,更多關(guān)于Value支持對(duì)象類型的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
圖解Java經(jīng)典算法冒泡排序的原理與實(shí)現(xiàn)
冒泡排序是一種簡(jiǎn)單的排序算法,它也是一種穩(wěn)定排序算法。其實(shí)現(xiàn)原理是重復(fù)掃描待排序序列,并比較每一對(duì)相鄰的元素,當(dāng)該對(duì)元素順序不正確時(shí)進(jìn)行交換。一直重復(fù)這個(gè)過程,直到?jīng)]有任何兩個(gè)相鄰元素可以交換,就表明完成了排序2022-09-09
SpringBoot整合MyBatis實(shí)現(xiàn)CRUD操作項(xiàng)目實(shí)踐
本文主要介紹了SpringBoot整合MyBatis實(shí)現(xiàn)CRUD操作項(xiàng)目實(shí)踐,如何實(shí)現(xiàn)數(shù)據(jù)庫(kù)的CRUD創(chuàng)建、讀取、更新、刪除操作,具有一定的參考價(jià)值,感興趣的可以了解一下2024-02-02
Java計(jì)算一個(gè)數(shù)加上100是完全平方數(shù),加上168還是完全平方數(shù)
這篇文章主要介紹了Java計(jì)算一個(gè)數(shù)加上100是完全平方數(shù),加上168還是完全平方數(shù),需要的朋友可以參考下2017-02-02
IDEA修改idea64.exe.vmoptions文件以及解決coding卡頓問題
IDEA修改idea64.exe.vmoptions文件以及解決coding卡頓問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04
RabbitMQ實(shí)現(xiàn)消費(fèi)端限流的步驟
消費(fèi)者端限流的主要目的是控制消費(fèi)者每次從 RabbitMQ 中獲取的消息數(shù)量,從而實(shí)現(xiàn)消息處理的流量控制,這篇文章主要介紹了RabbitMQ如何實(shí)現(xiàn)消費(fèi)端限流,需要的朋友可以參考下2024-03-03
使用JWT創(chuàng)建解析令牌及RSA非對(duì)稱加密詳解
這篇文章主要介紹了JWT創(chuàng)建解析令牌及RSA非對(duì)稱加密詳解,JWT是JSON Web Token的縮寫,即JSON Web令牌,是一種自包含令牌,一種情況是webapi,類似之前的阿里云播放憑證的功能,另一種情況是多web服務(wù)器下實(shí)現(xiàn)無狀態(tài)分布式身份驗(yàn)證,需要的朋友可以參考下2023-11-11

