代码之家  ›  专栏  ›  技术社区  ›  progonkpa

使用静态实例化方法在生成器类中自动连接依赖项

  •  1
  • progonkpa  · 技术社区  · 7 年前

    Article .

    我想自动连线/注入 ArticleMD5HashCalculator @Autowired 在球场上,IntelliJ抱怨说:不建议进行现场注射。构造函数注入是不可能的,因为它是一个生成器模式类,这意味着它有一个没有参数的私有构造函数和一个用于实例化的静态方法,在那里传递hashCalculator会很困难。

    新的hashCalculator结果是一个硬依赖,因此注入mock是不切实际的。处理这种情况的最佳方式是什么?

    import org.observer.media.utils.ArticleMD5HashCalculator;
    import org.observer.media.utils.MD5HashCalculator;
    
    import java.time.ZonedDateTime;
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    public class ArticleBuilder {
    
        private ArticleMD5HashCalculator hashCalculator;
    
        private String headline;
        private String subheading;
        private String lead;
        // other article fields...
    
        private ArticleBuilder() {
            // This seems wrong.
            this.hashCalculator = new ArticleMD5HashCalculator(new MD5HashCalculator());
        }
    
        public static ArticleBuilder article() {
            return new ArticleBuilder();
        }
    
        public ArticleBuilder withHeadline(String headline) {
            this.headline = headline;
            return this;
        }
    
        //Other with-methods...
    
        public Article build() {
            // calculateHash() is called in the 9th argument.
            return new Article(headline, subheading, lead, body, images, quotations, subArticles, url, calculateHash(), author, sources, category, subjects, index, medium, company, datePublished, dateFetched);
        }
    
        private String calculateHash() {
            return hashCalculator.hash(headline, subheading, lead, body, quotations, datePublished, dateFetched);
        }
    }
    
    3 回复  |  直到 7 年前
        1
  •  1
  •   yaswanth    7 年前

    假设:

    1. ArticleBuilder和ArticleMD5HashCalculator之间存在一对一的关系。这意味着您不打算在项目中的不同位置将hashCalculator的不同实例注入ArticleBuilder(基本上有多个ArticleBuilder实例)

    您可以按如下方式更改ArticleBuilder impl

    public class ArticleBuilder {
    
        private ArticleMD5HashCalculator hashCalculator;
    
        public ArticleBuilder(ArticleMD5HashCalculator hashCalculator) { 
            this.hashCalculator = hashCalculator;
        }
    }
    

    您可以创建类型为的SpringBean ArticleMD5HashCalculator 把它注射到一个 ArticleBuilder

    @Configuration
    public class ArticleConfig {
    
        @Bean
        public ArticleMD5HashCalculator articleMD5HashCalculator() {
            return new ArticleMD5HashCalculator(new MD5HashCalculator());
        }
    
        @Bean
        public ArticleBuilder() {
            return new ArticleBuilder(articleMD5HashCalculator());
        }
    }
    

    你可以自动连线 ArticleBuilder公司 并将其用作生成器。

    更新1:

    ArticleBuilder公司 在一个 Scraper 对象,并且您希望有一种获取新实例的方法 ArticleBuilder公司 每一次。你可以用弹簧 @Lookup 注释。

    的存根实现 刮刀

    public class Scraper {
    
    
        //assuming this is the method where you want to use ArticleBuilder
        public void scrape() {
            getArticleBuilder();
        }
    
        //You can even pass constructor arguments to this method. 
        //They will be used to match a constructor on the target bean and that gets invoked
        @Lookup
        public ArticleBuilder getArticleBuilder() {
            //Spring creates a runtime implementation of this method.
            return null;
        }
    }
    

    getArticleBuilder 只要你想要一个新的bean实例。如果它被声明为prototype,您将始终获得bean的新实例。

    但唯一需要注意的是,查找注释不适用于使用创建的bean @Bean 注释。你可能看起来像这样。

    @Component
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public class ArticleBuilder {
    
        @Autowired
        private ArticleMD5HashCalculator hashCalculator;
    
        public ArticleBuilder(ArticleMD5HashCalculator hashCalculator) { 
            this.hashCalculator = hashCalculator;
        }
    }
    
    @Component
    public class ArticleMD5HashCalculator {
    
        public ArticleMD5HashCalculator(MD5HashCalculator hashCalculator) {
            this.hashCalculator = hashCalculator;
        }
    }
    

    beans.xml:

    <beans>
        <bean class="MD5HashCalculator" /> 
        <!-- Fully qualified class name is needed -->
    </beans>
    
        2
  •  0
  •   Chlebik    7 年前

    此外,由于Spring文档中使用的约定,请尽可能使用基于构造函数的注入。

    Spring团队通常提倡构造函数注入,因为它使人们能够将应用程序组件实现为不可变对象,并确保所需的依赖项不为空。

    完整信息(滚动一点): Spring DOCS

        3
  •  0
  •   progonkpa    7 年前

    我想出了另一种方法来解决 new '并打开注入模拟的窗口。该解决方案意味着生成器必须由工厂实例化和重新创建。

    import org.observer.media.hash.ArticleHashCalculator;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.time.ZonedDateTime;
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    @Component
    public class ArticleBuilderFactory {
    
        private ArticleHashCalculator articleHashCalculator;
    
        @Autowired
        public ArticleBuilderFactory(ArticleHashCalculator articleHashCalculator) {
            this.articleHashCalculator = articleHashCalculator;
        }
    
        public ArticleBuilder create() {
            return new ArticleBuilder(articleHashCalculator);
        }
    
        public class ArticleBuilder {
    
            private ArticleHashCalculator articleHashCalculator;
    
            private String headline;
            private String subheading;
            //...
    
            private ArticleBuilder(ArticleHashCalculator articleHashCalculator) {
                this.articleHashCalculator = articleHashCalculator;
            }
    
            public ArticleBuilderFactory.ArticleBuilder withIndex(int index) {
                this.index = index;
                return this;
            }
    
            public ArticleBuilderFactory.ArticleBuilder withHeadline(String headline) {
                this.headline = headline;
                return this;
            }
            //...
    
            public Article build() {
                return new Article(headline, subheading, lead, body, images, quotations, subArticles, url, calculateHash(), author, sources, category, subjects, index, medium, company, datePublished, dateFetched);
            }
    
            private String calculateHash() {
                return articleHashCalculator.hash(headline, subheading, lead, body, quotations, datePublished, dateFetched);
            }
        }
    }
    

    工厂使用:

    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.observer.media.hash.ArticleMD5HashCalculator;
    import org.observer.media.hash.MD5HashCalculator;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringRunner;
    
    import static org.assertj.core.api.Java6Assertions.assertThat;
    
    @RunWith(SpringRunner.class)
    @ContextConfiguration(classes = {
            ArticleBuilderFactory.class,
            MD5HashCalculator.class,
            ArticleMD5HashCalculator.class
    })
    public class ArticleBuilderFactoryTest {
    
        private static final String HEADLINE = "headline";
        private static final String LEAD = "lead";
        private static final String BODY = "body";
    
        @Autowired
        private ArticleBuilderFactory articleBuilderFactory;
        @Autowired
        private ArticleMD5HashCalculator hashCalculator;
    
        @Test
        public void build() {
            ArticleBuilderFactory.ArticleBuilder articleBuilder = articleBuilderFactory.create();
            Article article = articleBuilder
                    .withHeadline(HEADLINE)
                    .withLead(LEAD)
                    .withBody(BODY)
                    .build();
    
            assertThat(article.getHeadline()).isEqualTo(HEADLINE);
            assertThat(article.getLead()).isEqualTo(LEAD);
            assertThat(article.getBody()).isEqualTo(BODY);
            assertThat(article.getHash()).isEqualTo(hashCalculator.hash(HEADLINE, null, LEAD, BODY, null, null, null));
        }
    }
    

    @Component
    public class ArticleMD5HashCalculator {
    }