【问题标题】:Spring - Injection of beans using Builder patternSpring - 使用 Builder 模式注入 bean
【发布时间】:2016-08-27 17:08:36
【问题描述】:

上下文

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

问题

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

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

一些代码sn-ps让问题更清楚:

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”实例注入“处理器”类。但要做到这一点,处理器必须是一个 bean,否则我必须使用诸如查找方法之类的东西。另一方面,无论我想在哪里使用处理器,我都必须这样做:

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

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

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

【问题讨论】:

  • 对不起,我还没有明白你的实际问题是什么。你能发布一些代码吗?比如那个班?这样,我们将更好地了解您拥有什么以及您想要什么......
  • 更新了问题。

标签: spring dependency-injection builder-pattern


【解决方案1】:

在保留构建器的同时,一种解决方案可能是简单地使构建器本身成为 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 配置同样适用。)

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

【讨论】:

  • 谢谢。你会建议我如何处理处理器的依赖项(例如:DaoBean)?另外,我不太明白您所说的“建设者有劣势..”是什么意思。我通常会验证构建函数中的参数。
  • 处理器的依赖,例如DaoBean,由 Spring 注入到 Builder 中,然后由 builder 提供给 Processor。 (我倾向于制作一个(可能是私有的)构造器,它采用 Builder 本身,因此不需要复杂的构造器签名或隐藏的 setter 方法)。而且我刚刚注意到,您没有机会告诉任何人“您可以选择 String、String、int 或 String、int 或只是 int”仅使用签名(在编译时),因此所有检查都必须在运行时完成(但这是 TDD 的一个非常小的缺点)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-07-10
  • 1970-01-01
  • 2011-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-06
相关资源
最近更新 更多