You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot自定义@ConfigValue注解注入失效问题求助

问题原因与解决方案

嘿,这个问题我之前踩过类似的坑,核心原因是Spring Bean的初始化顺序在搞鬼!

为什么MysqlConf的password无法注入?

你的MysqlConf是一个@Configuration配置类,Spring在启动时会优先处理配置类:

  1. 首先实例化MysqlConf
  2. 紧接着调用里面的druidDataSource()方法创建数据源Bean
  3. 而你的BeanPropertiesUtil是普通@Component,它的afterPropertiesSet方法要等自身初始化完成后才执行,这时候druidDataSource已经创建好了——你这时候给MysqlConf的password字段赋值,根本赶不上数据源的初始化,所以数据源里的password还是空的。

而MyAnnotationService是@Service,它的初始化时机比BeanPropertiesUtil的afterPropertiesSet晚,所以工具类处理它的时候,字段还没被用到,赋值后自然能正常获取。

解决方案:改用BeanPostProcessor处理自定义注解

BeanPostProcessor是Spring的核心扩展点,它能在每个Bean实例化完成后、初始化方法执行前对Bean做处理,完美覆盖配置类的场景。

修改BeanPropertiesUtil类

把原来的InitializingBean和BeanFactoryAware换成BeanPostProcessor:

@Component
public class BeanPropertiesUtil implements BeanPostProcessor {
    private static final Logger logger = LoggerFactory.getLogger(BeanPropertiesUtil.class);
    public static Map<String,Object> configMap = new HashMap<>();

    @PostConstruct
    public void init() throws Exception {
        configMap.put("spring.datasource.password","123321");
        configMap.put("orderNo","2018051929991");
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 在Bean初始化方法执行前注入字段
        Field[] declaredFields = bean.getClass().getDeclaredFields();
        for(Field field : declaredFields) {
            ConfigValue configValue = field.getAnnotation(ConfigValue.class);
            if(configValue != null) {
                field.setAccessible(true);
                try {
                    Object value = configMap.get(configValue.name());
                    logger.info("field name :"+field.getName() +" field value:"+value);
                    field.set(bean, value);
                } catch (IllegalAccessException e) {
                    logger.error("注入字段失败", e);
                }
            }
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 无需额外处理,直接返回Bean
        return bean;
    }
}

为什么这个方案有效?

  • postProcessBeforeInitialization会在所有Bean的初始化逻辑(包括@Configuration类的@Bean方法执行)之前被调用
  • 当Spring处理MysqlConf时,会先调用这个方法给password字段赋值,之后才会执行druidDataSource()创建数据源,这时候password已经有值了,数据源就能正确初始化。

额外优化建议

如果你的配置值不是硬编码,而是来自配置文件,建议通过Environment来读取,更符合Spring规范:

@Autowired
private Environment environment;

@PostConstruct
public void init() throws Exception {
    configMap.put("spring.datasource.password", environment.getProperty("spring.datasource.password"));
    // 其他配置项同理
}

内容的提问来源于stack exchange,提问作者Mr Cai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 09:01:02