Spring中如何通过工厂方法动态获取Bean并避免手动实例化?
问题描述
希望在工厂方法中实例化类并执行接口定义的方法,但不想手动创建嵌套依赖,让Spring自动注入依赖。现有代码如下:
接口与实现类
public interface BasicProcess { Message createProcess(); } @RequiredArgsConstructor public class WorkProcess implements BasicProcess { private final HelperService helperService; @Override public Message createProcess() { // 业务逻辑实现 } } @RequiredArgsConstructor public class EatProcess implements BasicProcess { private final FoodService foodService; @Override public Message createProcess() { // 其他业务逻辑实现 } }
当前工厂实现
@Service @RequiredArgsConstructor public class Factory { private final HelperService helperService; private final FoodService foodService; public BasicProcess factoryMethod(String param) { if ("Work".equals(param)) { return new WorkProcess(helperService); } else if ("Food".equals(param)) { return new EatProcess(foodService); } return null; } }
调用代码
@RequiredArgsConstructor @Component class SomeClass { private final Factory factory; public void startProcess() { BasicProcess process = factory.factoryMethod("Food"); process.createProcess(); // 调用EatProcess的实现 } }
需求:替换手动new实例化的方式,用Spring管理依赖注入,实现动态调用createProcess。
优化方案
方案1:将Process类声明为Spring Bean,用Map自动注入所有实现
把WorkProcess和EatProcess标记为Spring Bean,利用Spring自动收集同类型Bean到Map的特性,直接根据参数获取实例,完全避免手动实例化。
步骤1:修改Process类为Spring Bean
@Component("workProcess") // 指定Bean名称,用于后续参数匹配 @RequiredArgsConstructor public class WorkProcess implements BasicProcess { private final HelperService helperService; @Override public Message createProcess() { // 业务逻辑实现 } } @Component("eatProcess") @RequiredArgsConstructor public class EatProcess implements BasicProcess { private final FoodService foodService; @Override public Message createProcess() { // 其他业务逻辑实现 } }
步骤2:优化工厂类
Spring会自动将所有BasicProcess类型的Bean注入到Map中,key为Bean名称,value为对应实例:
@Service public class Factory { private final Map<String, BasicProcess> processMap; // 构造函数注入,Spring自动填充Map public Factory(Map<String, BasicProcess> processMap) { this.processMap = processMap; } public BasicProcess factoryMethod(String param) { BasicProcess process = switch (param) { case "Work" -> processMap.get("workProcess"); case "Food" -> processMap.get("eatProcess"); default -> throw new IllegalArgumentException("不支持的流程类型:" + param); }; if (process == null) { throw new IllegalArgumentException("未找到对应流程:" + param); } return process; } }
方案2:使用ApplicationContext动态获取Bean
如果不想提前指定Bean名称,可以直接注入ApplicationContext,根据类类型获取已完成依赖注入的实例:
@Service @RequiredArgsConstructor public class Factory { private final ApplicationContext context; public BasicProcess factoryMethod(String param) { return switch (param) { case "Work" -> context.getBean(WorkProcess.class); case "Food" -> context.getBean(EatProcess.class); default -> throw new IllegalArgumentException("不支持的流程类型:" + param); }; } }
方案3:自定义注解+BeanPostProcessor(复杂场景适配)
如果需要更灵活的匹配规则(比如用注解标记流程类型),可以通过自定义注解收集Bean:
自定义流程标记注解
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Component // 让Spring自动扫描该类 public @interface ProcessType { String value(); // 标记流程类型,如"Work"、"Food" }
修改Process类添加注解
@ProcessType("Work") @RequiredArgsConstructor public class WorkProcess implements BasicProcess { private final HelperService helperService; @Override public Message createProcess() { // 业务逻辑实现 } } @ProcessType("Food") @RequiredArgsConstructor public class EatProcess implements BasicProcess { private final FoodService foodService; @Override public Message createProcess() { // 其他业务逻辑实现 } }
实现BeanPostProcessor收集Bean
@Component public class ProcessRegistry implements BeanPostProcessor { private final Map<String, BasicProcess> processMap = new HashMap<>(); @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof BasicProcess) { ProcessType annotation = bean.getClass().getAnnotation(ProcessType.class); if (annotation != null) { processMap.put(annotation.value(), (BasicProcess) bean); } } return bean; } public BasicProcess getProcess(String type) { return processMap.get(type); } }
优化工厂类
@Service @RequiredArgsConstructor public class Factory { private final ProcessRegistry processRegistry; public BasicProcess factoryMethod(String param) { BasicProcess process = processRegistry.getProcess(param); if (process == null) { throw new IllegalArgumentException("不支持的流程类型:" + param); } return process; } }
总结
推荐使用方案1,它利用Spring原生特性实现最简洁的依赖注入,代码可读性和可维护性最高,所有Process实例都由Spring管理,完全避免手动new带来的依赖管理问题。
内容的提问来源于stack exchange,提问作者Roma Kap
相关产品推荐
相关产品推荐

