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

如何在运行时动态实例化含@Autowired依赖的Spring Bean

如何实例化运行时动态确定类型且内部包含@Autowired Bean的Spring Bean?

刚好遇到过类似的场景,针对你需要在运行时动态创建带@Autowired依赖的原型Bean的需求,Spring有几种原生的解决方案,结合你的代码示例给你详细说明:

核心问题解析

你不能直接用new ClientA()或new ClientB()创建实例,是因为手动new出来的对象不在Spring容器的管理范围内,Spring不会自动为它注入@Autowired标注的MyHelperService,导致依赖为null。而我们需要让Spring来负责Bean的创建,才能保证依赖注入完成,同时满足运行时动态确定类型、每个任务使用独立实例的要求。


方案1:注入ApplicationContext动态获取原型Bean

Spring的ApplicationContext自带Bean实例化能力,对于prototype作用域的Bean,每次调用getBean()都会返回全新的实例,并且自动完成内部依赖注入。

修改你的ClientFactory代码如下:

@Component
public class ClientFactory {
    @Autowired
    private ApplicationContext applicationContext;

    public Client createClient(String type) {
        // 根据传入的type动态匹配对应的Client实现类
        if ("A".equals(type)) {
            return applicationContext.getBean(ClientA.class);
        } else if ("B".equals(type)) {
            return applicationContext.getBean(ClientB.class);
        }
        // 可根据业务需求添加默认实现或抛出异常
        throw new IllegalArgumentException("不支持的Client类型: " + type);
    }
}

方案2:使用BeanFactory(更轻量的替代方案)

如果不想依赖功能更全但也更重的ApplicationContext,可以直接注入BeanFactory(它是ApplicationContext的父接口,仅提供Bean管理的核心能力),用法和上面完全一致:

@Component
public class ClientFactory {
    @Autowired
    private BeanFactory beanFactory;

    public Client createClient(String type) {
        if ("A".equals(type)) {
            return beanFactory.getBean(ClientA.class);
        } else if ("B".equals(type)) {
            return beanFactory.getBean(ClientB.class);
        }
        throw new IllegalArgumentException("不支持的Client类型: " + type);
    }
}

方案3:结合@Lookup注解(适合枚举型动态场景)

如果你的Client类型是可提前枚举的固定集合,还可以用Spring的@Lookup注解来定义原型Bean的获取方法,这种方式更符合Spring的依赖注入风格:

@Component
public abstract class ClientFactory {
    // Spring会自动实现这个抽象方法,返回全新的ClientA原型实例
    @Lookup
    protected abstract ClientA getClientA();

    @Lookup
    protected abstract ClientB getClientB();

    public Client createClient(String type) {
        if ("A".equals(type)) {
            return getClientA();
        } else if ("B".equals(type)) {
            return getClientB();
        }
        throw new IllegalArgumentException("不支持的Client类型: " + type);
    }
}

注意:这里ClientFactory必须是抽象类,因为@Lookup标注的方法需要Spring动态生成子类来实现实例逻辑。


适配你的多线程场景

你的实际业务是通过ExecutorService提交多线程任务,每个任务需要独立的Client实例,以上方案都能完美适配:

  • 每次从工厂获取的都是全新的prototype实例,任务执行完毕后实例生命周期结束,不会和其他任务的实例产生资源冲突;
  • MyHelperService作为单例Bean,只要它本身是线程安全的(这是Spring单例Bean的基本要求),就可以在多线程下安全复用。

修改后的MyService示例:

@Service
public class MyService {
    @Autowired
    private ClientFactory factory;

    @Autowired
    private ExecutorService executorService;

    public void processList(List<String> requests) {
        List<Callable<Void>> tasks = requests.stream()
                .map(request -> (Callable<Void>) () -> {
                    Client client = factory.createClient(request);
                    client.process(request);
                    return null;
                })
                .collect(Collectors.toList());
        
        try {
            executorService.invokeAll(tasks);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            // 根据业务需求处理中断异常
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 10:31:14