【问题标题】:Injecting different implementation of one interface inside an injected class在注入的类中注入一个接口的不同实现
【发布时间】:2020-04-09 23:12:04
【问题描述】:

假设我有两个名为VehicleBikeCar 的接口实现。我还有一个班级,名为TireStore。我还有另外两个类,我们将它们命名为PersonAPersonB。我想要做的是每当我在PersonA 中使用TireStore 时,我希望Car 被注入。每当我使用PersonB 时,我都希望BikeVehicle 的形式注入到TireStore。不知道有没有可能……

到目前为止,我已经尝试用@Qualifier("exampleQualifier")Car 来注释PersonA。然后我将Bike注释为@Primary

没用。搜索了一下,没有找到解决办法。

提前谢谢你。

它们的结构是这样的:

@Component
public class PersonA{

    private TireStore TireStore;

    public TireStore(TireStore tireStore){
        this.tireStore = tireStore;
    }
    ...
}
@Component
public class PersonB{

    private TireStore tireStore;

    public TireStore(TireStore tireStore){
        this.tireStore = tireStore;
    }
    ...
}
@Component
public class TireStore{

    private Vehicle vehicle;

    public TireStore(Vehicle vehicle){
        this.vehicle = vehicle;
    }
    ...
}
@Component
public class Bike extends Vehicle{
...
}
@Component
public class Car extends Vehicle{
...
}

【问题讨论】:

  • 详细阅读限定符的工作原理。解决方案就快完成了。
  • 另外,听起来你的设计不太有效。为什么人拥有TireStore?为什么TireStore 拥有Vehicle?为什么一个人只知道TireStore而不知道Vehicle?或者这只是minimal reproducible example 的任意示例?
  • 这只是我首先想到的事情的一个例子:)

标签: java spring dependency-injection


【解决方案1】:

我认为在处理此类问题时首先考虑的是重新考虑您的应用程序架构。因为使用 @Qualifier 注释将解决在多个 Bean 中连接相同接口的初始问题。但是,根据您的示例,如果没有紧密耦合的代码,很难将此类连接到您的 PersonAPersonB 类。 我将向您展示我的示例:

界面

public interface Vehicle(){
  //some methods you are using in this interface

}

自行车类:

@Component
public class Bike implements Vehicle{
  //here are the implemented methods from Vehicle Interface
}

汽车类:

@Component
public class Car implements Vehicle{
  //here are the implemented methods from Vehicle Interface
}

轮胎店类:

@Component
public class TireStore{

    private Vehicle vehicle;

    public TireStore(@Qualifier("bike") Vehicle vehicle){
      this.vehicle = vehicle;
    }
}

@Qualifier注解括号内的字符串是Bean的名字。基本上,您是专门告诉 Spring 您要自动装配哪个 Bean(谁正在使用 Vehicle 接口)。 这就是您可以使用 @Qualfier 注释至少部分解决问题的方法。

但是如何完全解决您的问题的答案是为每个服务创建单独的接口。这就是您可以避免使用被视为不好的做法

胖接口的方法

我会这样做: 对于 Bike 类,我将创建一个 BikeService 接口并将 Bike 类重命名为 BikeServiceImpl。 Car 类也是如此。

我会在你的 TireStore 类中实现这两个服务

@Component
public class TireStore{

  private final BikeService bikeServices;
  private final CarService carServices;

  public TireStore(BikeService bikeService, CarService carService){
    this.bikeService = bikeService;
    this.carService = carService;
  }

  // here are your methods 

}

现在如果你想将这个 TireStore 类连接到你的 PersonAPersonB bean 中,你可以这样做:

@Component
public class PersonA{

  private TireStore TireStore;

  public TireStore(TireStore tireStore){
    this.tireStore = tireStore;
  }

  ...
}

这样你将把你的 TireStore bean 注入到 PersonAPersonB 中。 bean 最好的方法是为 TireStore bean 创建一个接口,而不是在 PersonA bean 中通过它的接口自动装配 TireStore bean,如下所示:

public interface TireStoreService(){
  //some methods or empty
}

并像这样编辑您的 TireStore bean

@Component
public class TireStore implements TireStoreService{

  private final BikeService bikeServices;
  private final CarService carServices;

  public TireStore(BikeService bikeService, CarService carService){
    this.bikeService = bikeService;
    this.carService = carService;
  }

  // here are your methods 

}

现在您可以像这样将这个 TireService bean 自动装配到您的 PersonAPersonB 类中: 对于 PersonA bean:

@Component
public class PersonA{

  private TireStoreService tireStoreService;

  public TireStore(TireStoreService tireStoreService){
    this.tireStoreService = tireStoreService;
  }

  ...
}

PersonB bean 也是如此

附:避免使用空接口。如果你想使用有意义的接口连接你的服务/bean,你可以这样做,这样做是一个好习惯。但是,如果您没有任何接口可以使用,我建议您使用经典的基于构造函数的依赖注入

希望这会对您有所帮助。但是,如果我的回答太混乱或太糟糕,请发表评论,我会重新回答我的回答

【讨论】:

  • 感谢您的详细解答。不过,我在您的回答中错过了这一点,这将如何帮助 PersonA 始终使用注入 Car 的服务,而 PersonB 始终使用 Bike。
  • 这个问题的答案是改变你的应用程序的布局/架构。以标准方式,对此没有简单的解决方案。当您使用 PersonA 类或 PersonB 类时,也许您可​​以使用 if() 语句将带有特定 Car 或 Bike bean 的 TireStore bean 注入,但这不是一个好的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多