Spring - 使用构建器模式注入 bean

Spring - Injection of beans using Builder pattern

上下文

利用 Spring 4.1.7 的应用程序。所有配置都在 XML 文件中(不使用注释),我宁愿保持这种方式(但如果必须的话,我可以改变事情的完成方式)。

问题

我创建了一个新的 class,它带有构建器 class。

现在我想将其他 bean 注入到这个新的 class 中。我可能可以使用查找方法和类似的解决方案来做到这一点,然后在调用者 bean 中使用新的 class 构建器来创建一个实例。但是,我宁愿将这个新 class 的一个实例注入到它的调用者 bean,然后他们通过构建器创建一个。这是我不确定该怎么做的地方。例如,这对我来说看起来像一个抽象工厂,但我不知道如何在运行时将这些参数(传递给构建器)传递给抽象工厂,然后再传递给它构建的工厂。

一些代码片段使问题更清楚:

public final class Processor {

    private final StatusEnum newStatus;
    private final Long timeOut;

    // I'd like this to be be injected by Spring through its setter (below)
    private DaoBean daoInstance;

    private Processor() {
        this.newStatus = null;
        this.timeOut = null;
    }

    private Processor(Builder builder) {
        this.newStatus = builder.getNewStatus();
        this.timeOut = builder.getTimeOut();
    }

    // To be called by Spring
    public void setDaoInstance(DaoBean instance) {
        this.daoInstance = instance;
    }

    public void updateDatabase() {
        daoInstance.update(newStatus, timeOut);
    }

    // Builder class
    public static final class Builder {
        private StatusEnum newStatus;
        private Long timeOut;
        // lots of other fields

        public Long getTimeOut() {
             return this.timeOut;
        }

        public StatusEnum getNewStatus() {
             return this.newStatus;
        }

        public Builder withTimeOut(Long timeOut) {
             this.timeOut = timeOut;
             return this;
        }

        public Builder withNewStatus(StatusEnum newStatus) {
             this.newStatus = newStatus;
             return this;
        }

        public Processor build() {
             return new Processor(this);
        }
    }
}

我想将 "DaoBean" 的一个实例注入 "Processor" class。但是要做到这一点,处理器必须是一个 bean,否则我必须使用查找方法之类的东西。另一方面,无论我想在哪里使用处理器,我都必须这样做:

new Processor.Builder()
   .withTimeOut(1000L)
   .withNewStatus(StatusEnum.UPDATED)
   .build()
   .updateDatabase();

取而代之,我想知道我是否可以使处理器成为一个 bean,Spring 可以注入它的调用者同时保持其不变性。然后可以通过 Spring 将 DaoBean 实例注入处理器。这样我就可以将接线代码和业务逻辑分开。

值得一提的是,Builder 的字段多于 2 个,并非所有字段都必须设置。这就是为什么我认为抽象工厂是可行的方法(以不同方式构建处理器实例)。

一个解决方案,在保留构建器的同时,可能是简单地使构建器本身成为一个 Spring bean...

这允许这样的事情..

@Autowired
private Builder builder;

public void someMethod() {
    Result = builder.withX(...).doSomething();
}

这样,您的 Result 对象是不可变的,可以通过一个不错的构建器创建,并且构建器可以将 Spring bean(在您的例子中是 dao)注入其中,甚至没有人注意到它在那里。

唯一不同的是,您不自己创建构建器,而是让 Spring 为您创建...

@Component
@Scope("prototype") // normally a good idea
public static class Builder {
    @Autowired
    private DaoBean dao;

    // your logic here
}

(同样适用于 JavaConfig 或 XML 配置,如果您不想扫描。)

尤其是对于许多组合,我更喜欢构建器模式,因为工厂需要复杂的方法签名。当然,构建器的缺点是您无法在编译时检查给定的属性类型组合是否至少在理论上是可以接受的。好的,您可以使用各种构建器来模拟它,但这可能有点矫枉过正。