簡體   English   中英

Spring Beans中的構造函數參數太多

[英]Too many constructor arguments in Spring Beans

在我的代碼中有一個Bean Admin Admin的一個操作是創建Task開始它們。

Task執行的操作相當復雜。 因此它被分成幾個不同的Step類。

這就是我的代碼看起來的樣子

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

正如您所看到的,每個Step類都有2個或3個Bean依賴項。 步驟類不是Spring Beans,因此它們是來自Task的依賴項。 任務也不是Spring Bean,因此它從Admin獲取依賴關系。 這導致Admin有太多的依賴關系(~15)。

我試過這個: https//dzone.com/articles/autowiring-spring-beans-into-classes-not-managed-by-spring

基本上,您創建一個名為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分組並將抽象傳遞給Admin。 bean沒有任何我可以利用的邏輯分組。 此外,許多步驟需要對bean進行完全訪問(訪問界面中的所有方法)。 這會導致抽象變得臃腫。

您可以將Spring bean作為原型bean(因為它們是有狀態的,並且每次都需要一個不同的實例),並在Task bean中注入Provider<Step> (如果我理解的話,可以是單例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);
}

在Task bean中,您注入了一個ObjectProvider<Step1>

private ObjectProvider<Step1> stepProvider;

public Service(ObjectProvider<Step1> step1Provider) {
    this.stepProvider = stepProvider;
}

public void start() {
    Step1 step1 = step1Provider.getObject("a", "b");
    step1.do();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM