如何将@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-&gt;this.myServiceA = service) 更容易看。 或者:this.myServiceA = myServiceA.orElse(this.myServiceA);

以上是关于如何将@Autowired 构造函数参数分别设置为“required=false”的主要内容,如果未能解决你的问题,请参考以下文章

为啥我不能将类构造函数参数设置为默认值?

如何自动装配在 SpringBoot 应用程序中具有带参数的构造函数的组件

@Autowired 是啥,怎么使用呢?

@Autowired注解详解

@Autowired 注解有什么用?

如何将构造函数(可变参数)作为模板参数传递?