我正在考虑应该从字段值计算哈希值的此构建器类。也许对于初学者来说,这本身是错误的,但是在我眼下,它似乎属于那里,因为我正在努力追求一个不变的Article

我想自动接线/注入ArticleMD5HashCalculator,但是当我在字段上放置@Autowired时,IntelliJ抱怨:不建议进行字段注入。构造函数注入是不可能的,因为它是一个生成器模式类,这意味着它具有一个不带参数的私有构造函数和一个静态实例化方法,该方法将难以在hashCalculator中传递。

将助洗剂注入刮板中。刮板将为许多文章重复使用同一生成器。当Spring使用原型范围创建构建器时,当下一篇文章不覆盖旧值时,构建器将携带旧值。

新的hashCalculator结果是一个严格的依赖关系,这使得注入模拟不切实际。处理这种情况的最佳方法是什么?

这是现在的代码:

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

最佳答案

假设:


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


您可以按以下方式更改ArticleBuilder隐式

public class ArticleBuilder {

    private ArticleMD5HashCalculator hashCalculator;

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


您可以创建类型为ArticleMD5HashCalculator的spring bean,并通过以下方式将其注入类型为ArticleBuilder的spring bean。

@Configuration
public class ArticleConfig {

    @Bean
    public ArticleMD5HashCalculator articleMD5HashCalculator() {
        return new ArticleMD5HashCalculator(new MD5HashCalculator());
    }

    @Bean
    public ArticleBuilder() {
        return new ArticleBuilder(articleMD5HashCalculator());
    }
}


您可以在项目中的其他地方自动连接ArticleBuilder并将其用作构建器。

我不确定为什么要创建一个私有构造函数和一个静态方法来调用它。我认为这是因为您想要一个单例的ArticleBuilder。可以通过上述方法来实现。如果我对此有误,请纠正我。

更新1:

根据您在注释中提供的信息,您正在将ArticleBuilder注入到Scraper对象中,并且希望有一种每次获取新的ArticleBuilder实例的方法。您可以为此使用spring @Lookup批注。

Scraper类的存根实现。

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


您可以在任何时候想要一个新的bean实例时调用getArticleBuilder。如果声明为原型,则将始终获得该bean的新实例。

但是唯一需要注意的是,Lookup注释不适用于使用@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>

08-19 04:32