Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java SpringBean中的构造函数参数太多_Java_Spring_Dependency Injection - Fatal编程技术网

Java SpringBean中的构造函数参数太多

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

在我的代码中有一个Bean管理员。Admin的操作之一是创建任务并启动它们

由任务执行的操作相当复杂。因此,它被分为几个不同的步骤类

这就是我的代码的外观

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();
}