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

如何在Spring的Condition/ConfigurationCondition中注入Bean依赖?

解决方案:在Spring条件判断中依赖Bean或动态控制配置类

Spring的Condition/ConfigurationCondition是在Bean定义解析、注册的早期阶段执行的,此时绝大多数业务Bean还未实例化,所以直接通过@Autowired或BeanFactory获取Bean必然失败。以下是几种可行的替代方案:

方案一:直接在Condition中查询数据库(不依赖Bean)

既然核心需求是通过数据库判断,可跳过中间Bean,直接在Condition里读取数据库配置、建立连接执行查询。这种方式完全在条件评估阶段完成,不依赖任何Bean实例。

public class MyCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment env = context.getEnvironment();
        // 从配置中读取数据库参数
        String dbUrl = env.getProperty("spring.datasource.url");
        String dbUser = env.getProperty("spring.datasource.username");
        String dbPwd = env.getProperty("spring.datasource.password");
        String driverClass = env.getProperty("spring.datasource.driver-class-name", "com.mysql.cj.jdbc.Driver");

        try {
            Class.forName(driverClass);
            // 执行查询判断是否启用配置
            try (Connection conn = DriverManager.getConnection(dbUrl, dbUser, dbPwd);
                 PreparedStatement stmt = conn.prepareStatement("SELECT enable FROM system_config WHERE config_key = 'my_config_enable'");
                 ResultSet rs = stmt.executeQuery()) {
                return rs.next() && rs.getBoolean("enable");
            }
        } catch (ClassNotFoundException | SQLException e) {
            // 异常场景默认禁用配置
            return false;
        }
    }
}

方案二:用BeanDefinitionRegistryPostProcessor动态注册配置类

如果必须复用MyBean的逻辑,可放弃@Conditional,改用BeanDefinitionRegistryPostProcessor。这个处理器在所有Bean定义注册完成后、实例化前执行,可手动初始化MyBean并根据结果动态注册MyConfig。

@Component
public class MyConfigRegistrar implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) registry;
        // 手动实例化MyBean(需确保其依赖的Bean定义已注册)
        MyBean myBean = beanFactory.createBean(MyBean.class);
        
        boolean shouldEnable = myBean.checkIfMyConfigShouldEnable();
        if (shouldEnable) {
            // 注册MyConfig的Bean定义
            BeanDefinition configDef = BeanDefinitionBuilder.genericBeanDefinition(MyConfig.class).getBeanDefinition();
            registry.registerBeanDefinition("myConfig", configDef);
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 无需额外操作
    }
}

注意:若MyBean有复杂依赖,需确保这些依赖的Bean定义已完成注册,否则createBean会抛出异常。

方案三:结合@ConditionalOnBean与SpEL表达式

如果MyBean无循环依赖且可提前初始化,可使用@ConditionalOnBean确保MyBean存在,再通过@ConditionalOnExpression调用其方法判断:

@Configuration
@ConditionalOnBean(MyBean.class)
@ConditionalOnExpression("#{myBean.checkIfMyConfigShouldEnable()}")
public class MyConfig {
    // 配置类内容
}

风险提示:若MyBean依赖MyConfig中的Bean,会触发循环依赖;需确保MyBean的初始化时机早于条件评估。

方案四:监听上下文事件动态调整Bean

允许在上下文初始化完成后再决定的话,可监听ContextRefreshedEvent(此时所有Bean已实例化),通过MyBean判断后动态注册/销毁MyConfig:

@Component
public class MyConfigActivator implements ApplicationListener<ContextRefreshedEvent> {
    @Autowired
    private MyBean myBean;
    @Autowired
    private ConfigurableApplicationContext context;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        boolean shouldEnable = myBean.checkIfMyConfigShouldEnable();
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        
        if (shouldEnable && !beanFactory.containsBean("myConfig")) {
            MyConfig myConfig = beanFactory.createBean(MyConfig.class);
            beanFactory.registerSingleton("myConfig", myConfig);
        } else if (!shouldEnable && beanFactory.containsBean("myConfig")) {
            ((DefaultSingletonBeanRegistry) beanFactory).destroySingleton("myConfig");
        }
    }
}

缺点:MyConfig的Bean会延迟到上下文初始化完成后才注册,可能影响依赖它的Bean的启动时机。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 05:05:39