Clark To Do The blog of Clark

构造(Constructor)注入还是设值(Setter)注入?

构造(Constructor)注入

使用构造(Constructor)注入需要将依赖作为构造函数的参数, 由于构造函数必须被调用, 因此强制的保证了依赖的初始化, 并且也将代码的依赖管理与 Spring 解耦, 实现了容器无关.

从 Spring 4.3 开始, 在只有一个构造器的类上, @Autowired注解可以不需要显示指定. 这是特别优雅的, 因为它使得类将不携带任何容器注释. 基于此点, 同样从 Spring 4.3 开始, @Configuration也开始支持构造(Constructor)注入, 并且在单构造器的情况下不需要指定@Autowired

import javax.inject.Inject;

public class Foo {

    private Bar bar;

    @Inject
    public Foo(Bar bar) {
        this.bar = bar;
    }

}

设值(Setter)注入

使用设值(Setter)注入, setter是否被调用具有不确定性, 因此对象实例可能永远不会得到依赖的组件. 唯一的方式是将@Autowired@Inject等注解添加到setter上, 同时也打破了容器无关性.

import javax.inject.Inject;

public class Foo {

    private Bar bar;

    @Inject
    public void setBar(Bar bar) {
        this.bar = bar;
    }
}

Spring Team 推荐

由于可以将构造(Constructor)注入设值(Setter)注入混合使用, 因此将构造(Constructor)注入作为必填依赖的策略, 设值(Setter)注入作为可选依赖的策略会是一个不错的做法. 同时, 在setter使用@Required注解可以将依赖变为必需的依赖.

Spring team 主张使用构造(Constructor)注入, 因为它实现了将不可变对象作为应用组件, 从而保证了必需的依赖不能为空. 此外, 构造(Constructor)注入组件总是会返回包含完全状态的客户端(调用端)代码. 附注一点: 大量的构造参数是一个坏的代码味道,这意味着该类可能包含了太多的责任,应该进行重构以更好进行关注点分离。

设值(Setter)注入应当主要用于可选依赖的管理, 这些依赖可以被赋以合理的默认值. 否则, 所有使用到该依赖的位置都要添加非空检测. 设值(Setter)注入的好处则是setter方法使得对象实例可以被重复配置和注入. 通过JMX管理通过设值(Setter)注入的依赖就是一个引人注目的方式.

对于一个特定的类需要使用最合理的依赖注入方式. 有时, 当使用第三方没有源码的类时, 选择就已经为你做好了. 例如: 如果一个第三方类没有暴露出setter方法, 这时构造(Constructor)注入就是唯一的选择了.

comments powered by Disqus