Java SpringBean中的构造函数参数太多
在我的代码中有一个Bean管理员。Admin的操作之一是创建任务并启动它们 由任务执行的操作相当复杂。因此,它被分为几个不同的步骤类 这就是我的代码的外观Java SpringBean中的构造函数参数太多,java,spring,dependency-injection,Java,Spring,Dependency Injection,在我的代码中有一个Bean管理员。Admin的操作之一是创建任务并启动它们 由任务执行的操作相当复杂。因此,它被分为几个不同的步骤类 这就是我的代码的外观 public interface Admin{ void start(); //other methods } public class AdminImpl implements Admin{ private BeanA bean1; private BeanB bean2; //other fie
public interface Admin{
void start();
//other methods
}
public class AdminImpl implements Admin{
private BeanA bean1;
private BeanB bean2;
//other fields
public Admin(BeanA bean1,
BeanB bean2,
BeanC bean3
//Lot more parameters
BeanO bean15
){
this.bean1 = bean1;
this.bean2 = bean2;
//and so on
}
public void start(){
return new Task(bean1, bean2, bean3,...).start()
}
//other methods
}
public class Task{
private BeanA bean1;
private BeanB bean2;
//other fields
public Task(BeanA bean1,
BeanB bean2,
BeanC bean3
//Lot more parameters
){
//bind parameters to fields
}
public void start(){
new Step1(bean1, bean2,.. other parameters).do();
new Step2(bean3, bean7,.. other parameters).do();
//more steps
}
}
@Configuration
public class MyConfiguration{
@Bean
public Admin admin(BeanA bean1, BeanB bean2....){
return new AdminImpl(bean1, bean2...);
}
}
正如您所看到的,每个步骤类都有2到3个Bean依赖项。Step类不是Springbean,所以它们是从Task传递的依赖项。Task也不是Springbean,因此它从Admin获取依赖项。
这导致管理员有太多的依赖项(~15)
我试过这个:
基本上,您创建了一个名为BeanUtil的服务Bean,它是ApplicationContextAware。静态方法getBean使用ApplicationContext获取bean
步骤类现在如下所示:
class Step{
public Step(){
BeanA bean1 = BeanUtil.getBean(BeanA.class);
BeanB bean2 = BeanUtil.getBean(BeanB.class);
}
public void do(){
//do stuff
}
}
这解决了最初的问题,但随后我在测试中遇到了困难。
这就是测试类现在的样子
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
public class Step1Test extends AbstractTestNGSpringContextTests {
@Test
public void test(){
Step1 step = new Step().do();
}
@Configuration
static class MockConfiguration {
@Bean
public BeanA beanA() {
BeanA mockBeanA=Mockito.mock(BeanA.class);
// set behavior of mock
return mockBeanA;
}
@Bean
public BeanUtil beanUtil(){
return new BeanUtil();
}
}
}
如果不创建不同的配置类,就无法更改不同测试用例的模拟行为。这感觉就像是通过创造另一个问题来解决一个问题
这是Spring开发人员面临的一个常见问题吗?更高抽象级别的类最终会有太多依赖项?还是我的设计有问题?处理或避免这种情况的正确方法是什么
其他问题看似相似,但并非如此
我从user7得到的一个建议是将BeanX分组,并将抽象传递给管理员。这些bean没有任何我可以利用的逻辑分组。此外,许多步骤需要对bean进行完全访问(访问接口中的所有方法)。这将导致抽象变得臃肿。您可以将steps Spring Bean作为原型Bean(因为它们是有状态的,每次都需要不同的实例),并将
提供者
注入到任务Bean中(如果我理解正确,可以是单例Bean)
例如:
public class Step1 {
private Bean1 bean1;
private Bean2 bean2;
private final String someValue;
private final String someOtherValue;
public Step(String someValue, String someOtherValue) {
this.someValue = someValue;
this.someOtherValue = someOtherValue;
}
@Autowired
public void setBean1(Bean1 bean1) {
this.bean1 = bean1;
}
@Autowired
public void setBean2(Bean2 bean2) {
this.bean2 = bean2;
}
do() {
// ...
}
}
然后,在配置类中,将各个步骤定义为bean,方法应包含所需的参数:
@Bean
@Scope("prototype")
public Step1 step1(String someValue, String someOtherValue) {
return new Step(someValue, someOtherValue);
}
在任务bean中,您注入了一个对象提供者
:
私有对象提供者;
公共服务(ObjectProvider step1Provider){
this.stepProvider=stepProvider;
}
公开作废开始(){
Step1Step1=step1Provider.getObject(“a”、“b”);
步骤1.do();
}
有没有一种方法可以将单个的BeanXs
分组,并将分组后的抽象注入AdminImpl?这是一个有效的建议,但不幸的是,我不能使用它。我已经在帖子中详细回应了。你所说的是什么意思?许多步骤需要完全访问bean(访问接口中的所有方法)
?每个步骤只需要几个bean就可以传递给它,对吗?为什么不能将步骤作为bean来执行?有没有理由不希望步骤成为spring bean?这将是一个显而易见的解决办法。这样,您的步骤就可以使用构造函数注入,并且可以对它们进行测试。在我的例子中,任务还需要是一个原型bean,但这很好。在示例步骤类中,您使用setter作为bean依赖项,使用构造函数作为运行时参数。所有这些都可能在构造函数中吗?是的,但是您需要在配置类中声明或自动连接BeanXxx bean,以便能够将它们作为参数传递给StepXxx构造函数。我已经在配置类中自动连接了BeanXs。没关系。我不知道如何让spring在传递其余参数(运行时参数)的同时传递一些构造函数参数(bean)。我想这个问题应该已经在某个地方得到了回答,但是我找不到。好吧,新的步骤1(bean1,bean2,someValue,someOtherValue)
。您可以访问bean1和bean2,因为它们是自动连接的,您可以访问someValue和someOtherValue,因为它们是@Bean
-注释方法的参数。
private ObjectProvider<Step1> stepProvider;
public Service(ObjectProvider<Step1> step1Provider) {
this.stepProvider = stepProvider;
}
public void start() {
Step1 step1 = step1Provider.getObject("a", "b");
step1.do();
}