如何基于命令行输入创建Spring Bean并解决String类型Bean找不到的报错
错误原因
你当前的写法中DataProvider对应的@Bean默认是单例(Singleton)作用域,Spring容器启动阶段就会尝试实例化这个Bean,此时需要注入方法参数中的两个String类型的Bean,而你的容器中没有对应类型的Bean,因此抛出找不到java.lang.String类型Bean的错误。你的需求是运行时拿到命令行参数后才创建实例,默认单例模式不符合你的使用场景。
解决方案
方案1:修改Bean为原型作用域
给DataProvider的@Bean方法加上原型作用域注解,Spring启动时不会提前实例化该Bean,只有当你调用getBean传入参数时才会创建实例:
import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; @Configuration public class SpringConfig { @Bean @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public DataProvider getDataProvider(String filePath, String mnhPath) throws Exception { return new DataProvider(filePath, mnhPath); } }
其他代码无需修改,运行时调用beanFactory.getBean(DataProvider.class, arguments.one(), arguments.two())就可以正常拿到实例。
注意:如果你需要在其他单例Bean中注入
DataProvider,不要直接注入实例,而是注入ObjectProvider<DataProvider>,在需要使用的时候调用objectProvider.getObject(arg1, arg2)获取实例,避免单例Bean启动时提前创建DataProvider实例导致报错。
方案2:运行时手动实例化后纳入Spring管理
如果你不需要在其他Bean中提前注入DataProvider,可以直接去掉SpringConfig中DataProvider的@Bean定义,在拿到命令行参数后手动创建实例,若需要Spring处理该实例的依赖注入、生命周期回调等逻辑,可以用AutowireCapableBeanFactory处理:
@Autowired private AutowireCapableBeanFactory beanFactory; @Override public void run(final String... args) throws Exception { final CommandLineArgs arguments = new CommandLineArgs(); CmdLineParser parser = new CmdLineParser(arguments); parser.parseArgument(args); // 手动创建实例 DataProvider dataProvider = new DataProvider(arguments.one(), arguments.two()); // 若需要Spring处理该实例的@Autowired注入、初始化回调等逻辑,添加下面这行 dataProvider = (DataProvider) beanFactory.initializeBean(dataProvider, "dataProvider"); dataProvider.doSomeOperation(); }
这个方案逻辑更直观,不需要额外配置Bean作用域,适合绝大多数运行时动态创建实例的场景。
内容的提问来源于stack exchange,提问作者user1298426

