java - 有没有办法注入(inject)一个依赖项,该依赖项将根据注入(inject)的位置(使用 Spring 引导)使用特定的 bean?

标签 java spring spring-boot dependency-injection

我有一个服务(我们称它为 TaskExecutorService),它需要一个依赖项 TaskService。 我习惯于通过构造函数注入(inject)依赖,所以我使用了以下代码:

@Service
class TaskExecutorService {
  private final TaskService taskService;

  public TaskExecutorService(TaskService taskService) {
     this.taskService = taskService;
  }

  void function1() {...}
  void function2() {...}
}

TaskService 有一个依赖项TaskRetrieverService,它是一个接口(interface),由多个用@Service 注释的“检索器”实现。

@Service
class TaskService {
  private final TaskRetrieverService taskRetrieverService;

  public TaskService(TaskRetrieverService taskRetrieverService) {
     this.taskRetrieverService = taskRetrieverService;
  }
}

TaskExecutorService 中注入(inject) TaskService 并选择使用哪个检索器的最佳方法是什么? 此外,我的实际用例是根据 TaskExecutorService 中的函数(function1function2),我希望能够使用“猎犬”或其他。

我认为我可以使用其构造函数直接在方法中实例化 TaskService,但我希望有一个最好的方法来执行此操作。

最佳答案

我同意这是某种反模式,因为您正在连接 @Bean,但我需要这样做几次并且没有义务对接口(interface)实现进行硬编码。

答案是,您可以在使用 @Bean(name = "customName") 在 Spring Config 中声明 bean 时为其命名。这样,您就可以选择要使用的接口(interface)实现

对于以下示例(根据您的情况),我有一个名为 Dependency.java 的接口(interface)依赖项。对于这个例子,让我们保持简单,它只有一个方法 print(),它会根据我们在运行时使用的实现打印一些东西。

public interface Dependency {
    void print();
}

对于这种依赖,我有两种可能的实现方式。它们是 Child1Child2

这是Child1.java

public class Child1 implements Dependency {
    @Override
    public void print() {
        System.out.println("I'm Child1!");
    }
}

这是Child2.java

public class Child2 implements Dependency {
    @Override
    public void print() {
        System.out.println("I'm Child2!");
    }
}

如您所见,它们仅从我们的 Dependency.java 中实现,不做任何其他事情。他们实现该方法,该方法打印一条语句以区分正在运行时实现的方法。

然后我有一个名为 SpringConfig.java

的 Spring Config 类
@Configuration
@ComponentScan("you.packages.go.here.for.discovery.**.*")
public class SpringConfig {

    @Bean(name = "myBean1")
    public Dependency dependency() {
        return new Child1();
    }

    @Bean(name = "myBean2")
    public Dependency dependency2() {
        return new Child2();
    }

}

在这里,我声明了 2 个 bean,每个 bean 都有一个唯一名称。对于此示例,第一个实现 (Child1) 将称为 myBean1,第二个实现 (Child2) 将称为 myBean2.

然后我有了 @Service 类,它将使用这两个 @Beans 之一。 我使用 Spring 在此处连接 Context,而不是使用 new Child1() 进行硬连接。这样我就可以根据逻辑选择我想选择的。

@Service
public class MyService implements ApplicationContextAware {

    private ApplicationContext context;

    public void useDependency() {
        Dependency dependency = (Dependency) context.getBean("myBean2");
        dependency.print();
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }
}

上下文由 implements ApplicationContextAware 实现。这将添加保存 ApplicationContextsetApplicationContext() 方法。有了这个上下文后,您只需选择要在上一行中使用哪个接口(interface)实现

Dependency dependency = (Dependency) context.getBean("myBean2");

如果您将 myBean2 更改为 myBean1 (或您在 SpringConfig 的参数 @Bean 中设置的任何其他名称(name = "something") 你会将运行时实现更改为那个 @Bean)。

我实现了 @Bean myBean2,所以正如预期的那样,这将打印

"I'm Child2!"

关于java - 有没有办法注入(inject)一个依赖项,该依赖项将根据注入(inject)的位置(使用 Spring 引导)使用特定的 bean?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63941645/

相关文章:

java - 具有多个数据源的 hibernate 配置类

java - Spring Boot 测试 - 让应用程序运行更长时间

node.js - React + Spring Boot 部署

java - 在 Java 中获取集合的各个条目?

java - 如何建立对中介颁发的 X.509 证书的信任?

java - 在 Java 中创建 SSL 连接

java - 使用 log4j2 进行 Spring 启动。配置 log4j2 Spring-lookup

Java:ResultSet getString() 因环境而异

java - 简单的 Spring MVC+安全设置

java - 通过restTemplate进行JUnit模拟外部休息调用