【发布时间】:2014-02-08 13:50:21
【问题描述】:
我正在尝试重构一些应用程序以使用 Spring DI 而不是纯 java 并遇到问题。
基本上我有一个有几个构造函数的类:
public MyClass() {
this(new A());
}
public MyClass(A a) {
this(a, new B()));
}
public MyClass(String string) {
this(new A(string));
}
public MyClass(A a, B b) {
this.a = a;
this.c = a.getC();
this.b = b;
this.d = b.getD();
}
public MyClass(A a, B b, D d) {
this.a = a;
this.c = a.getC();
this.b = b;
this.d = d;
}
这些构造函数用在很多地方,其中一些在代码中,一些在测试中,等等。
现在,我正在介绍基于 Spring Java 的应用程序配置:
@Configuration
public class ApplicationConfiguration {
@Bean
MyClass myClass() {
return null;
}
}
并尝试通过从应用程序上下文中获取 bean 来重写所有地方:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfiguration.class);
MyClass myClass = (MyClass) context.getBean("myClass", arg1, arg2);
问题是在某些地方我只有 arg1,在某些地方既有 arg1 也有 arg2,在某些地方我没有 args。那么,我该如何在应用程序配置中表达呢?
bean 也是单调的,所以如果我创建了几个具有不同参数的 bean,那么这个要求就会被打破,即
@Configuration
public class ApplicationConfiguration {
@Bean
MyClass myClass1() {
return new MyClass();
}
@Bean
MyClass myClass2(A a) {
return new MyClass(a);
}
//etc
}
绝对不是解决办法。
提前致谢
更新。 看起来 +Avi 答案是正确的,但我仍然不明白如何正确地做事。
我创建了一个 junit4 测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ApplicationConfiguration.class)
public class MyTest {
@Autowired
private ApplicationContext applicationContext;
@Before
public void setupMyClass() {
// myClass = new MyClass();
myClass = (MyClass) applicationContext.getBean("myClass");
}
}
所以,这里我想在测试中使用 MyClass,所以在 Avi 答案中没有类似 Foo 的 bean。
我为“不同的场景修改了上下文,在每个场景中,您需要使用不同的参数构造 MyClass - 您需要创建多个 bean,每个都实例化自己的 MyClass”(我用错误的方式理解了这个短语,但是这就是我的想法):
@Configuration
public class ApplicationConfiguration {
//Note: beans have the same name
@Bean
MyClass myClass() {
return new MyClass();
}
@Bean
MyClass myClass(A a) {
return new MyClass(a);
}
//etc
}
但现在还有另一个问题:applicationContext.getBean("myClass") 返回我随机(取决于具有相同名称和参数的 bean 的数量)bean 而不是没有参数的 bean。当我指定 args - applicationContext.getBean("myClass", new Object[]{});它说我只允许原型范围的bean。但我想要一个单例 bean。
看起来我需要另一个建议:如何在配置中删除多个具有相同名称的 bean?也许我需要一个聪明的工厂,或者@Autowired(required=false) 可以在这里提供帮助?
即使我在测试中有类似 Foo 的对象,我应该如何在测试中使用它?
@Configuration
@Import(ApplicationConfiguration.class)
public class FooConfiguration {
@Autowire
MyClass myClass; //but which one constructor?
@Bean
Foo foo() {
return new Foo(myClass);
}
}
我不想在每个配置本身中创建 MyClass,我只想拥有一个,我可以导入它...
更新2。
好的,我删除了所有构造函数,只留下了一个,它具有所有参数
@Configuration
public class ApplicationConfiguration {
@Bean
MyClass myClass(A a, B b, C c, D d) {
return new MyClass(a, b, c, d);
}
}
现在我正在测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = MyTest.TestConfiguration.class)
public class MyTest {
@Configuration
@Import(ApplicationConfiguration.class)
static class TestConfiguration {
@Bean
A a() {
return new A();
}
@Bean
B b() {
return new B();
}
@Bean
C c() {
return b().getC();
}
@Bean
D d() {
return c().getD();
}
}
@Autowired
private MyClass myClass;
}
但是现在,我不明白如何避免为每个测试都写这个..
【问题讨论】:
标签: java spring dependency-injection refactoring inversion-of-control