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,也可方便快捷的看到本人的博客哦,谢谢~

 

posted @   zhangdaopin  阅读(434)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示