Spring - 使用Builder模式注入bean

时间:2016-08-27 17:08:37

标签: spring dependency-injection builder-pattern

上下文

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

问题

我创建了一个带有构建器类的新类。

现在我想将其他bean注入这个新类。我可以使用查找方法和类似的解决方案来执行此操作,然后在调用方bean中使用新类的构建器来创建实例。但是,我宁愿将这个新类的实例注入其调用者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”类。但要做到这一点,处理器必须是一个bean或者我必须使用像查找方法这样的东西。另一方面,无论我想在哪里使用处理器,我都必须做这样的事情:

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

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

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

1 个答案:

答案 0 :(得分:0)

在保留构建器的同时,一个解决方案可能只是简单地使Builder本身成为一个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配置相同,如果您不想扫描。)

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