Springboot - @ConfigurationProperties用法示例简介
项目中需要增加一个新的功能,从而需要在原来的配置文件中动态的增加或者减少配置的信息,如URL,之前使用@ConfigurationProperties注解配置过map格式的参数,如果是URL的话,只需要使用List格式就可以了,试着做一下,gogogo
1、需要在类上增加注解 如:
2、需要在添加注解的类,编写对应参数的属性和get方法(必须加上get方法,否则会读不到对应的配置参数)
@RestController
@ConfigurationProperties(prefix = "cluster")
//@EnableConfigurationProperties(RestController.class) ##上面一行会在IDEA中报一个警告,有blog说需要加上这一个注解,但是我这里加上后,会消除上一行注解的警告,但是会导致项目启动失败,所以我将它注释掉了
public class GatewayRestController {
private List<String> clusterAddr = new ArrayList<>();
public List<String> getClusterAddr() { return clusterAddr; }
... ...
}
3、需要在你的配置文件如application.yaml中增加配置:
##这种方式可能用起来更‘爽’
cluster:
clusterAddr:
- "http://127.0.0.1:11001/synRequest"
- "http://127.0.0.2:11001/synRequest"
##下面这种方式也可以,更加直观
##cluster:
##clusterAddr[0]: "http://127.0.0.1:11001/synRequest"
##clusterAddr[1]: "http://127.0.0.2:11001/synRequest"
##clusterAddr[2]: "http://127.0.0.3:11001/synRequest"
##clusterAddr[3]: "http://127.0.0.4:11001/synRequest"
如何接受Map格式的配置参数呢?gogogo
1、需要在类上增加注解 如:
2、需要在添加注解的类,编写对应参数的属性和get方法(必须加上get方法,否则会读不到对应的配置参数)
@Service
@ConfigurationProperties(prefix = "cluster")
//@EnableConfigurationProperties(ServiceImpl.class) ##此处注释掉的原因同上
public class ServiceImpl implements Service {
private HashMap<String, String> pool = new HashMap<>();
public HashMap<String, String> getPool() {
return pool;
}
... ...
}
3、需要在你的配置文件如application.yaml中增加配置:
cluster:
pool:
test-1: http://127.0.0.1:9001/
test-2: http://127.0.0.1:9002/
test-3: http://127.0.0.1:9003/
test-4: http://127.0.0.1:9004/
test-5: http://127.0.0.1:9005/
test-6: http://127.0.0.1:9006/
test-7: http://127.0.0.1:9007/
test-8: http://127.0.0.1:9008/
test-9: http://127.0.0.1:9009/
用起来是爽的,我们吧啦吧啦源码看看,到底是怎样实现的呢?
我们知道,SpringBoot在启动时默认会加载一些类,其中包含了AbstractAutowireCapableBeanFactory, 从而触发了applyBeanPostProcessorsBeforeInitialization接口,applyBeanPostProcessorsBeforeInitialization接口中调用了ConfigurationPropertiesBindingPostProcessor的postProcessBeforeInitialization接口。
applyBeanPostProcessorsBeforeInitialization接口:
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
Object result = existingBean;
Iterator var4 = this.getBeanPostProcessors().iterator();
do {
if (!var4.hasNext()) {
return result;
}
BeanPostProcessor beanProcessor = (BeanPostProcessor)var4.next();
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
} while(result != null);
return result;
}
postProcessBeforeInitialization接口:若存在ConfigurationProperties注解,则执行postProcessBeforeInitialization接口
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
ConfigurationProperties annotation = (ConfigurationProperties)AnnotationUtils.findAnnotation(bean.getClass(), ConfigurationProperties.class); //方式一
if (annotation != null) {
this.postProcessBeforeInitialization(bean, beanName, annotation);
}
annotation = (ConfigurationProperties)this.beans.findFactoryAnnotation(beanName, ConfigurationProperties.class);//方式二
if (annotation != null) {
this.postProcessBeforeInitialization(bean, beanName, annotation);
}
return bean;
}
postProcessBeforeInitialization接口:
private void postProcessBeforeInitialization(Object bean, String beanName, ConfigurationProperties annotation) {
PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory(bean);
factory.setPropertySources(this.propertySources);
factory.setValidator(this.determineValidator(bean));
factory.setConversionService(this.conversionService == null ? this.getDefaultConversionService() : this.conversionService);
if (annotation != null) {
factory.setIgnoreInvalidFields(annotation.ignoreInvalidFields());
factory.setIgnoreUnknownFields(annotation.ignoreUnknownFields());
factory.setExceptionIfInvalid(annotation.exceptionIfInvalid());
factory.setIgnoreNestedProperties(annotation.ignoreNestedProperties());
if (StringUtils.hasLength(annotation.prefix())) {
factory.setTargetName(annotation.prefix());
}
}
try {
factory.bindPropertiesToTarget(); //进行属性绑定
} catch (Exception var8) {
String targetClass = ClassUtils.getShortName(bean.getClass());
throw new BeanCreationException(beanName, "Could not bind properties to " + targetClass + " (" + this.getAnnotationDetails(annotation) + ")", var8);
}
}
通过PropertiesConfigurationFactory的bindPropertiesToTarget进行属性绑定:target是需要进行属性绑定的object
public void bindPropertiesToTarget() throws BindException {
Assert.state(this.propertySources != null, "PropertySources should not be null");
try {
if (logger.isTraceEnabled()) {
logger.trace("Property Sources: " + this.propertySources);
}
this.hasBeenBound = true;
this.doBindPropertiesToTarget();
} catch (BindException var2) {
if (this.exceptionIfInvalid) {
throw var2;
}
logger.error("Failed to load Properties validation bean. Your Properties may be invalid.", var2);
}
}
private void doBindPropertiesToTarget() throws BindException {
RelaxedDataBinder dataBinder = this.targetName != null ? new RelaxedDataBinder(this.target, this.targetName) : new RelaxedDataBinder(this.target);
if (this.validator != null && this.validator.supports(dataBinder.getTarget().getClass())) {
dataBinder.setValidator(this.validator);
}
if (this.conversionService != null) {
dataBinder.setConversionService(this.conversionService);
}
dataBinder.setAutoGrowCollectionLimit(2147483647);
dataBinder.setIgnoreNestedProperties(this.ignoreNestedProperties);
dataBinder.setIgnoreInvalidFields(this.ignoreInvalidFields);
dataBinder.setIgnoreUnknownFields(this.ignoreUnknownFields);
this.customizeBinder(dataBinder);
Iterable<String> relaxedTargetNames = this.getRelaxedTargetNames();
Set<String> names = this.getNames(relaxedTargetNames);
PropertyValues propertyValues = this.getPropertySourcesPropertyValues(names, relaxedTargetNames);
dataBinder.bind(propertyValues); //属性绑定
if (this.validator != null) {
dataBinder.validate();
}
this.checkForBindingErrors(dataBinder);
}
参考文档:Spring Boot Reference Documentation
参考博客:Spring Boot 之 @ConfigurationProperties
微信公众号,搜索:zhangdaopin,也可方便快捷的看到本人的博客哦,谢谢~
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南