如何将@Autowired构造函数参数单独设置为"required = false"

jcg*_*cia 38 spring constructor autowired spring-boot

@Autowired@Configuration类构造函数下使用注释.

@Configuration
public class MyConfiguration {

   private MyServiceA myServiceA;
   private MyServiceB myServiceB

   @Autowired
   public MyConfiguration(MyServiceA myServiceA, MyServiceB myServiceB){
     this.myServiceA = myServiceA;
     this.myServiceB = myServiceB;    
   }
}
Run Code Online (Sandbox Code Playgroud)

作为Spring文档sais,我能够声明是否需要带注释的依赖项.

如果我@Autowired在构造函数下标记注释required=false,我是说要自动装配的两个服务不是必需的(如Spring文档所示):

@Autowired(required = false)
public MyConfiguration(MyServiceA myServiceA, MyServiceB myServiceB){
  this.myServiceA = myServiceA;
  this.myServiceB = myServiceB;   
}
Run Code Online (Sandbox Code Playgroud)

从Spring文档:

在多参数方法的情况下,'required'参数适用于所有参数.

如何required单独为每个构造函数参数设置属性?是否有必要@Autowired在每个领域下使用注释?

问候,

Str*_*lok 44

如果您使用的是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});   
}
Run Code Online (Sandbox Code Playgroud)

  • @AndrewTobilko如果他正在考虑"可选"依赖关系,OP肯定会检查空值.你也可以拥有可选字段.许多方法可以确保您不会获得NPE. (10认同)
  • 可选择的是前进的方式,IMO.从构造函数中可以很容易地看到依赖项是什么以及哪些是可选的,而无需查看所有setter.我认为在构造函数体中`this.myServiceA = myServiceA.orElse(null)`比`myServiceA.ifPresent(service - > {this.myServiceA = service})`更容易. (6认同)
  • 我不希望使用`Optional`,但是感谢您的回答;) (2认同)
  • 这看起来是一件完美的事情,但是 Intellij 的 Idea 给出了关于在方法参数中使用Optional的警告。 (2认同)

Dan*_*ski 29

明确的方法

基本上,您有一个bean,它具有一些必需和可选的依赖项.处理此场景的推荐方法,不仅是配置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;
   }

}
Run Code Online (Sandbox Code Playgroud)

使用这种方法,您可以轻松地对类进行单元测试,而无需任何模拟库.您可以使用构造函数和可选的setter在测试状态中创建对象.

@Autowired(required = false)直接在球场上和去除二传也将工作,但由于您使用的是构造器注入,我想你想的状态依存更加明确.

额外的想法

您还可以考虑使用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);
   }

}
Run Code Online (Sandbox Code Playgroud)

有些人反对在Optional类属性中使用类型(主要是因为Brian Goetz的回答),但最终应该是整个团队决定在项目上工作.

  • 请注意,示例中只有一个构造函数.第二个注释是在setter方法上.您可以根据需要注释任意数量的setter. (4认同)

小智 14

从 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;    
   }
}
Run Code Online (Sandbox Code Playgroud)


Cza*_*zar 13

从Spring 4.3.0.RC1开始,您可以这样做:

public MyConfiguration(MyServiceA myServiceA, @Autowired(required = false) MyServiceB myServiceB){
  this.myServiceA = myServiceA;
  this.myServiceB = myServiceB;   
}
Run Code Online (Sandbox Code Playgroud)

随着ElementType.PARAMETER加入作为注释目标.

  • 我使用它的方式与之完全相同,但与@Qualifier一起使用时,仍然得到`没有可用的'java.util.Properties'类型的合格bean:期望至少有1个合格的autowire候选bean。 (2认同)