如何基于配置条件初始化Bean?自定义工厂依赖优化求助
问题描述
现有一个CustomFactory工厂类,需要根据config.property的值创建,当前代码如下:
@Service @RequiredArgsConstructor @ConditionalOnProperty("'${config.property}==a' or '${config.property}==b'") public class CustomFactory { private final SpecificActionOnA specificActionOnA; private final SpecificActionOnB specificActionOnB; }
为了让这个Bean能成功创建,不得不给每个SpecificAction组件添加相同的条件:
@Component @ConditionalOnProperty("'${config.property}==a'or '${config.property}==b'") public class SpecificActionOnA {} @Component @ConditionalOnProperty("'${config.property}==a' or '${config.property}==b'") public class SpecificActionOnB {}
期望改为:SpecificActionOnA仅在config.property为a时加载,SpecificActionOnB仅在config.property为b时加载,即:
@Component @ConditionalOnProperty("'${config.property}==a'") public class SpecificActionOnA {} @Component @ConditionalOnProperty("'${config.property}==b'") public class SpecificActionOnB {}
但不想为这两种情况创建单独的工厂类,该如何实现?
解决方案
方法1:使用Optional注入依赖
将工厂类的依赖改为Optional类型,Spring会自动注入存在的Bean,不存在的则为空Optional,避免因某个Bean未加载导致工厂类无法创建:
@Service @RequiredArgsConstructor @ConditionalOnProperty("'${config.property}==a' or '${config.property}==b'") public class CustomFactory { private final Optional<SpecificActionOnA> specificActionOnA; private final Optional<SpecificActionOnB> specificActionOnB; // 业务方法中根据配置值获取对应实例 public Object getAction(@Value("${config.property}") String propertyValue) { if ("a".equals(propertyValue)) { return specificActionOnA.orElseThrow(() -> new IllegalStateException("SpecificActionOnA未加载")); } else if ("b".equals(propertyValue)) { return specificActionOnB.orElseThrow(() -> new IllegalStateException("SpecificActionOnB未加载")); } throw new IllegalArgumentException("不支持的config.property值"); } }
方法2:使用@Autowired(required = false)
将依赖注入标记为非必填,Spring会忽略不存在的Bean。注意需要替换@RequiredArgsConstructor为手动构造函数,因为前者会强制要求所有final字段必须被注入:
@Service @ConditionalOnProperty("'${config.property}==a' or '${config.property}==b'") public class CustomFactory { private final SpecificActionOnA specificActionOnA; private final SpecificActionOnB specificActionOnB; public CustomFactory( @Autowired(required = false) SpecificActionOnA specificActionOnA, @Autowired(required = false) SpecificActionOnB specificActionOnB ) { this.specificActionOnA = specificActionOnA; this.specificActionOnB = specificActionOnB; } // 业务方法中校验并返回对应实例 public Object getAction(@Value("${config.property}") String propertyValue) { if ("a".equals(propertyValue)) { Objects.requireNonNull(specificActionOnA, "SpecificActionOnA未加载"); return specificActionOnA; } else if ("b".equals(propertyValue)) { Objects.requireNonNull(specificActionOnB, "SpecificActionOnB未加载"); return specificActionOnB; } throw new IllegalArgumentException("不支持的config.property值"); } }
方法3:接口+策略模式(扩展性更强)
如果后续可能新增更多SpecificAction类型,推荐先定义公共接口,将具体实现抽象化,工厂类无需感知具体实现类:
- 定义公共接口:
public interface SpecificAction { // 定义业务方法 void execute(); }
- 修改具体实现类:
@Component @ConditionalOnProperty("'${config.property}==a'") public class SpecificActionOnA implements SpecificAction { @Override public void execute() { // 实现A对应的逻辑 } } @Component @ConditionalOnProperty("'${config.property}==b'") public class SpecificActionOnB implements SpecificAction { @Override public void execute() { // 实现B对应的逻辑 } }
- 重构工厂类:
@Service @ConditionalOnProperty("'${config.property}==a' or '${config.property}==b'") public class CustomFactory { private final SpecificAction currentAction; // 根据配置值注入对应的实现类 public CustomFactory(@Value("${config.property}") String propertyValue, List<SpecificAction> actionList) { this.currentAction = actionList.stream() .filter(action -> { if ("a".equals(propertyValue)) return action instanceof SpecificActionOnA; if ("b".equals(propertyValue)) return action instanceof SpecificActionOnB; return false; }) .findFirst() .orElseThrow(() -> new IllegalStateException("无对应SpecificAction实现")); } public SpecificAction getCurrentAction() { return currentAction; } }
这种方式下,新增SpecificAction实现时只需添加对应的条件注解,无需修改工厂类,扩展性更好。
内容的提问来源于stack exchange,提问作者Severin Mbekou
相关产品推荐
相关产品推荐

