Java 从命令行创建带参数bean的惯用方法?
例如,在我的spring应用程序中,我需要几个DBWorker bean:Java 从命令行创建带参数bean的惯用方法?,java,spring,javabeans,Java,Spring,Javabeans,例如,在我的spring应用程序中,我需要几个DBWorker bean: @Component @Scope("prototype") class DBWorker { @Autowired JdbcTemplate templ; @Autowired SomeOtherDependency dep; public void init() { // use jdbcTemplate to pull some
@Component
@Scope("prototype")
class DBWorker {
@Autowired
JdbcTemplate templ;
@Autowired
SomeOtherDependency dep;
public void init() {
// use jdbcTemplate to pull some
// set up info from DB
}
public void run() {
// pull maxNumberOfRows and print out
}
private int maxNumberOfRowsToPull;
public void setMaxNumberOfRowsToPull() { .... }
}
所以基本上我有一个类DBWorker,它需要一系列依赖项,比如jdbctemplate。让Spring注入这些依赖项很方便,所以我将这些依赖项标记为@Autowired。在我的应用程序中,我需要3个位于不同位置的dbworker,它们对jdbcTemplate和其他依赖项具有相同的依赖关系。但是它们每个都有不同的maxNumberOfRowsToPull,它们都是由命令行args设置的
我需要在DBWorker上执行的逻辑步骤包括:
实例化3个工人
对每个工作进程调用init()
对每个工作进程调用run()
因为maxNumberOfRowsToPull来自命令行(不是固定的),所以我不能将它放在spring config.xml中或使用@Value注释,即使我可以在config中使用${system.property.name},这对于3个工作者来说是不同的,我必须设置系统属性3次才能间接地将其设置为setMaxNumberOfRowsToPull(),这很难看。
所以我必须直接调用setMaxNumberOfRowsToPull()。然后在调用之前,工作进程的“状态”是不完整的,所以在显式调用setMaxNumberOfRowsToPull()之前,我不能调用init(),所以我不能将init()逻辑放入构造函数中,也必须显式调用init()。另一方面,我想自动连接依赖项,因此我必须通过spring创建worker(否则依赖项将不会被注入)。总的来说,我现在拥有的最好的代码是:
DBWorker worker1 = (DBWorker) context.getBean(DBWorker.class);
// now the dependencies are already injected
worker1.setMaxNumberOfRowsToPull(args[0]);
worker1.setSomeOtherProperty(args[1]);
worker1.init();
worker1.run();
// then similar sequence for worker2 etc.
丑陋的部分是,如果我从命令行到集合有更多的属性,我会有更多像setMaxNumberOfRowsToPull()这样的调用,并且大多数工作程序共享相同的参数,只有少数需要显式更改。所以我将这些属性的@Value设置为system属性,并让Spring处理它。因此,每个workerbean从Spring出来时都带有一些“默认”属性设置(由命令行给出),我必须显式地调用一些属性设置来更改默认值。这听起来有点可疑,因为创建后的一些bean处于“错误”状态。我宁愿让每个bean在概念上被创建时都是正确的
我还必须手动调用这个init(),因为我必须等待手动调用属性设置。假设init()应该是springbean initialization()的一部分,我不需要为每个dbworker执行这个机械步骤
理想情况下,我想要更干净的东西,比如
DBWorker worker1 = context.getBean(DBWorker.class, args[0], args[1]);
// here the init() has been run inside constructor or in bean initialization()
worker1.run();
// then repeat above for worker2, worker3 ...
我想知道对于这样的场景,组织代码的惯用和干净的方法是什么。
谢谢 为什么不把变量放在init上呢
public void init(String numberOfRowsToPull, String otherProp) {
// use jdbcTemplate to pull some
// set up info from DB
this.numberOfRowsToPull = numberOfRowsToPull;
this.otherProp = otherProp;
}
大体上:
DBWorker worker1 = context.getBean(DBWorker.class);
worker1.init(args[0], args[1]);
worket1.run();
这是标准,我在很多地方都遇到过,它的作用与构造函数相同,以防您想要更改默认值
希望有帮助
编辑:
BeanFactory
有一个getBean(字符串名、对象…参数)
我没有试过,但这应该可以帮你
getBean("dBWorker", args[0], args[1]);
您可能会考虑使用JavaCon FIG来实例化和配置bean,将值注入配置类。javaconfig看起来确实是一个不错的选择,因为它提供了更多的灵活性。但是JavaConfig中的@Bean如何访问命令行参数呢?到目前为止,我所看到的唯一可以在链中传递值的方法是系统属性,但如果我们这样做,基本上在应用程序上,您将最终调用类似的步骤(尽管为我们保存init()调用)init(args[0],args[1])将起作用。我只是有点保留,因为这些属性是标准的getter和setter,代表bean的“属性”,而init()有点暗示“运行某个一次性操作”。我编辑了我的答案,并添加了一些我认为会帮助您请求的内容。。这东西应该有用。使用BeanFactoryah代替applicationContext!谢谢这正是我想要的。为什么我从来不知道getBean()的args形式。。。。