java - 使用静态实例化方法在构建器类中 Autowiring 依赖项

标签 java spring autowired builder

我正在考虑这个构建器类,它应该根据字段值计算哈希值。对于初学者来说,也许这本身就是错误的,但目前在我看来,它属于那里,因为我正在努力写一篇不可变的文章

我想 Autowiring /注入(inject)ArticleMD5HashCalculator,但是当我将@Autowired放在字段上时,IntelliJ提示:不建议进行字段注入(inject)。构造函数注入(inject)是不可能的,因为它是一个构建器模式类,这意味着它有一个不带参数的私有(private)构造函数和一个用于实例化的静态方法,在该方法中传入 hashCalculator 会很尴尬。

构建器被注入(inject)到刮刀中。抓取工具将为许多文章重复使用相同的构建器。当 Spring 创建具有原型(prototype)范围的构建器时,当下一篇文章不覆盖旧值时,构建器将携带旧值。

新建 hashCalculator 结果是一种硬依赖,因此注入(inject)模拟是不切实际的。处理这种情况的最佳方法是什么?

这是现在的代码:

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

最佳答案

假设:

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

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

public class ArticleBuilder {

    private ArticleMD5HashCalculator hashCalculator;

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

您可以创建 ArticleMD5HashCalculator 类型的 spring bean并将其注入(inject) ArticleBuilder 类型的 spring bean 中以下方式。

@Configuration
public class ArticleConfig {

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

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

您可以 Autowiring ArticleBuilder在项目的其他地方并将其用作构建器。

我不知道为什么你创建了一个私有(private)构造函数和一个静态方法来调用它。我认为这是因为您想要一个单例 ArticleBuilder。通过上述方法就可以实现这一点。如果我的理解有误,请纠正我。

更新1:

根据您在评论中提供的信息,您正在注入(inject) ArticleBuilderScraper对象,并且您希望有一种方法来获取 ArticleBuilder 的新实例每次。您可以使用 Spring @Lookup对此的注释。

Scraper 的 stub 实现类。

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 的新实例。

但唯一需要注意的是,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>

关于java - 使用静态实例化方法在构建器类中 Autowiring 依赖项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45188315/

相关文章:

grails - Grails从环境文件访问属性

spring - 使用注释按名称 Autowiring spring bean

php - 无法在 Symfony 中使用 Autowiring 获取 Doctrine EntityManager

java - 从行中获取 id

java - 什么是NullPointerException,我该如何解决?

java - 如何访问 Selenium 中弹出的表单类型登录/注册

java - Spring jpa 在返回实体对象时更改实体 boolean 变量名称

java - 使用 Spring Data REST 的 JsonMappingException : Selects wrong serializer when @Id is removed from the list that that is being mapped

java - 如何使用 Jackson 自动解析 Spring Boot 应用程序中的 JSON

java - 从 S3 上的视频创建缩略图而无需下载