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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 15:02:07