如何将@Autowired 构造函数参数分别设置为“required=false”
Posted
技术标签:
【中文标题】如何将@Autowired 构造函数参数分别设置为“required=false”【英文标题】:How to set @Autowired constructor params as "required=false" individually 【发布时间】:2017-06-27 08:50:28 【问题描述】:我在@Configuration
类构造函数下使用@Autowired
注释。
@Configuration
public class MyConfiguration
private MyServiceA myServiceA;
private MyServiceB myServiceB
@Autowired
public MyConfiguration(MyServiceA myServiceA, MyServiceB myServiceB)
this.myServiceA = myServiceA;
this.myServiceB = myServiceB;
作为Spring documentation sais,我可以声明是否需要带注释的依赖项。
如果我将构造函数下的@Autowired
注释标记为required=false
,我是说不需要自动装配的两个服务(如Spring 文档所述): p>
@Autowired(required = false)
public MyConfiguration(MyServiceA myServiceA, MyServiceB myServiceB)
this.myServiceA = myServiceA;
this.myServiceB = myServiceB;
来自 Spring 文档:
在多参数方法的情况下,'required'参数是 适用于所有参数。
如何将required
属性分别设置为每个构造函数参数?每个字段下都需要@Autowired
注解吗?
问候,
【问题讨论】:
你应该使用: - 强制依赖的构造函数注入 - 可选依赖的 Setter 注入 【参考方案1】:从 Spring 4.3.0.RC1 开始,您可以这样做:
public MyConfiguration(MyServiceA myServiceA, @Autowired(required = false) MyServiceB myServiceB)
this.myServiceA = myServiceA;
this.myServiceB = myServiceB;
ElementType.PARAMETER
被添加为注释目标。
从 Spring 5.0 开始,@Autowired(required = false)
也可以替换为 @Nullable
,或者可以使用 Kotlin 可为空的类型而无需任何注释,例如MyServiceB?
【讨论】:
我完全一样使用它,但与@Qualifier 一起使用,仍然得到No qualifying bean of type 'java.util.Properties' available: expected at least 1 bean which qualifies as autowire candidate.
【参考方案2】:
从 Spring Framework 5.0 开始,您还可以使用 @Nullable 注释(任何包中的任何类型 — 例如,来自 JSR-305 的 javax.annotation.Nullable):
@Configuration
public class MyConfiguration
private MyServiceA myServiceA;
private MyServiceB myServiceB
@Autowired
public MyConfiguration(@Nullable MyServiceA myServiceA, MyServiceB myServiceB)
this.myServiceA = myServiceA;
this.myServiceB = myServiceB;
【讨论】:
【参考方案3】:显式方法
基本上,您有一个具有一些必需和可选依赖项的 bean。处理这种情况的推荐方法,不仅是配置 bean,还包括其他任何情况,是仅为强制依赖项创建一个构造函数,并为可选依赖项使用 setter 注入。
public class MyConfiguration
private final MyServiceA myServiceA;
private MyServiceB myServiceB
@Autowired
public MyConfiguration(MyServiceA myServiceA)
this.myServiceA = myServiceA;
@Autowired(required = false)
public void setMyServiceB(MyServiceB myServiceB)
this.myServiceB = myServiceB;
使用这种方法,您可以轻松地对类进行单元测试,而无需任何模拟库。您可以使用构造函数和可选设置器创建处于测试状态的对象。
将@Autowired(required = false)
直接放在字段上并删除setter 也可以,但由于您使用的是构造函数注入,我假设您希望更明确地声明依赖关系。
补充想法
您还可以考虑使用 Optional 类型来包装非强制依赖项。开发人员通常假设如果一个类有一个属性,就应该设置它,这在您的场景中显然是不正确的。为了更清楚地标记特定依赖项不存在的可能性,您可能可以使用 Optional:
public class MyConfiguration
private final MyServiceA myServiceA;
private Optional<MyServiceB> myServiceB
@Autowired
public MyConfiguration(MyServiceA myServiceA)
this.myServiceA = myServiceA;
this.myServiceB = Optional.empty();
@Autowired(required = false)
public void setMyServiceB(MyServiceB myServiceB)
this.myServiceB = Optional.ofNullable(myServiceB);
有些人反对将Optional
类型用于类属性(主要是因为answer from Brian Goetz),但归根结底,应该由整个团队做出决定项目。
【讨论】:
对不起,但正如 Spring 文档所说:“任何给定 bean 类的只有一个构造函数(最多)可以带有此注释,指示构造函数在用作 Spring bean 时自动装配” 请注意,示例中只有一个构造函数。第二个注释在 setter 方法上。您可以根据需要注释任意数量的 setter。 我的错,我没有将第二种方法视为二传手。当然,我知道我可以注释尽可能多的 setter 和尽可能多的属性......但这是我想要避免的! 恕我直言,这是一个非常清晰和好的方法,应该是“要走的路”。【参考方案4】:如果您使用的是 Java 8 和 Spring Framework 4,则可以使用Optional
。
@Autowired
public MyConfiguration(Optional<MyServiceA> myServiceA, Optional<MyServiceB> myServiceB)
myServiceA.ifPresent(service->this.myServiceA = service);
myServiceB.ifPresent(service->this.myServiceB = service);
【讨论】:
以后会导致NPE @AndrewTobilko 如果他正在考虑“可选”依赖项,那么 OP 肯定会检查空值。你也可以只有可选字段。许多方法可以确保您不会获得 NPE。 我不喜欢使用Optional
,但感谢您的回答;)
可选是前进的方向,IMO。可以很容易地从构造函数中查看依赖项是什么以及哪些是可选的,而无需查看所有的 setter。我认为在构造函数主体中this.myServiceA = myServiceA.orElse(null)
比myServiceA.ifPresent(service->this.myServiceA = service)
更容易看。
或者:this.myServiceA = myServiceA.orElse(this.myServiceA);
以上是关于如何将@Autowired 构造函数参数分别设置为“required=false”的主要内容,如果未能解决你的问题,请参考以下文章