繁体   English   中英

我可以在 Spring 中注入一个 bean 的所有实现的 Map

[英]Can I inject Map of all impl of a bean in Spring

我正在编写一个获取输入的服务,我需要根据该输入调用一个服务的某些实现。 此输入是需要调用的实现的名称列表。

public interface Processor {

  Map<String, String> execute();

} 

@Service("BUCKET_PROCESSOR")
public class BucketProcessor implements Processor {
   ..... //first impl
}

@Service("QUERY_PROCESSOR")
public class QueryProcessor implements Processor {
   ..... //second impl
}

@Service("SQL_PROCESSOR")
public class SQLProcessor implements Processor {
   ..... //third impl
}

然后我有一个服务,我想在其中注入所有这些 impl 的映射,以便我可以遍历输入并调用相应的 impl。

@Service
public class MyAysncClient {

    @Autowired
    private Map<String, Processor> processorMap;  

    public void execute(List<String> processors) {

        List<Future> tasks = new ArrayList<>();

        for (String p : processors) {
            final Processor processor = this.processorMap.get(p);
            processor.execute()

            ....
        }

    }
}

是的,您可以 - spring 默认启用此功能。 即,您可以定义将Map<String, Processor>注入 spring bean。

这将指示 spring 查找作为Processor接口实现的所有 bean,这些 bean 将是映射的值,相应的键将是 bean 名称。

所以问题中提供的代码应该可以工作。

检查著名的@Autowired注释的文档。

在“自动装配数组、集合和映射”一节中,它说明了以下内容:

在数组、集合或映射依赖类型的情况下,容器自动装配与声明的值类型匹配的所有 bean。 为此,必须将映射键声明为 String 类型,该类型将解析为相应的 bean 名称。 这样一个容器提供的集合将被排序,考虑目标组件的 Ordered 和 @Order 值,否则按照它们在容器中的注册顺序。 或者,单个匹配的目标 bean 也可能是一般类型的 Collection 或 Map 本身,因此被注入。

请参阅此示例- 相关部分是将地图注入测试的位置。

一个更好更优雅的方法是使用以下代码定义Service locator pattern

@Configuration
public class ProcessorConfig {
    @Bean("processorFactory")
    public FactoryBean<?> serviceLocatorFactoryBean() {
        ServiceLocatorFactoryBean factoryBean = new ServiceLocatorFactoryBean();
        factoryBean.setServiceLocatorInterface(ProcessorFactory.class);
        return factoryBean;
    }
}

public interface ProcessorFactory {
    Processor getProcessor(ProcessorTypes processorTypes);
}

然后

public interface Processor {
    Map<String, String> execute();
}

@Component(ProcessorTypes.ProcessorConstants.BUCKET_PROCESSOR)
@Slf4j
public class BucketProcessor implements Processor {

    @Override
    public Map<String, String> execute() {
        return Collections.singletonMap("processor","BUCKET_PROCESSOR");
    }
}

@Component(ProcessorTypes.ProcessorConstants.QUERY_PROCESSOR)
@Slf4j
public class QueryProcessor implements Processor {

    @Override
    public Map<String, String> execute() {
        return Collections.singletonMap("processor","QUERY_PROCESSOR");
    }
}

@Component(ProcessorTypes.ProcessorConstants.SQL_PROCESSOR)
@Slf4j
public class SqlProcessor implements Processor {

    @Override
    public Map<String, String> execute() {
        return Collections.singletonMap("processor","SQL_PROCESSOR");
    }
}

现在定义您的服务注入工厂

@Service
@RequiredArgsConstructor
@Slf4j
public class ProcessorService {
    private final ProcessorFactory processorFactory;

    public void parseIndividual(ProcessorTypes processorTypes) {
        processorFactory
                .getProcessor(processorTypes)
                .execute();
    }

    public void parseAll(List<ProcessorTypes> processorTypes) {
        processorTypes.forEach(this::parseIndividual);
    }
}

在客户端,您可以通过以下方式执行

processorService.parseAll(Arrays.asList(ProcessorTypes.SQL, ProcessorTypes.BUCKET, ProcessorTypes.QUERY));
processorService.parseIndividual(ProcessorTypes.BUCKET);

如果您想公开为 REST API,您可以通过以下方式进行

@RestController
@RequestMapping("/processors")
@RequiredArgsConstructor
@Validated
public class ProcessorController {
    private final ProcessorService processorService;

    @GetMapping("/process")
    public ResponseEntity<?> parseContent(@RequestParam("processorType") @Valid ProcessorTypes processorTypes) {
        processorService.parseIndividual(ProcessorTypes.BUCKET);
        return ResponseEntity.status(HttpStatus.OK).body("ok");
    }

    @GetMapping("/process-all")
    public ResponseEntity<?> parseContent() {
        processorService.parseAll(Arrays.asList(ProcessorTypes.SQL, ProcessorTypes.BUCKET, ProcessorTypes.QUERY));
        return ResponseEntity.status(HttpStatus.OK).body("ok");
    }
}

希望您的问题通过解决方案得到解决

你可以只使用getBeansOfType(Processor.class)

返回具有匹配 bean 的 Map,包含 bean 名称作为键和相应的 bean 实例作为值

    @Bean
    public Map<String, Processor> processorMap(ApplicationContext context) {
        return context.getBeansOfType(Processor.class);
    }

我认为这会对您有所帮助,将 bean 配置添加到配置文件中

@Bean(name = "mapBean")
public Map<String, Processor > mapBean() {
    Map<String, Processor > map = new HashMap<>();
    //populate the map here 
    return map;
}

在您的服务中

@Service
public class MyAysncClient {

    @Autowired
    @Qualifier("mapBean")
    private Map<String, Processor> processorMap;  

    public void execute(List<String> processors) {

        List<Future> tasks = new ArrayList<>();

        for (String p : processors) {
            final Processor processor = this.processorMap.get(p);
            processor.execute()

            ....
        }

    }
}

顺便说一句,如果您不需要 bean 的名称(根据您的示例),请定义一个列表,spring 将在同一接口上注入所有定义为服务的 bean

@Autowired 
private List<Processor> processors; // include all defined beans

之后迭代它们中的每一个并调用execute方法。

是的,您可以,但它需要对您当前的代码进行一些改进才能使其以这种方式工作。 首先,您必须将getProcessorName方法添加到Processor接口:

public interface Processor {
  Map<String, String> execute();

  String getProcessorName();
} 

当你实现它时,你应该在getProcessorName方法的返回中设置它的名称

@Service
public class QueryProcessor implements Processor {
   //...

   @Override
   public String getProcessorName() {
      return "QUERY_PROCESSOR";
   }
}

然后你必须创建一个 spring 配置或将 bean 创建添加到现有的配置中

@Configuration
public class MyShinyProcessorsConfiguration {

   @Bean
   @Qualifier("processorsMap")
   public Map<String, Processor> processorsMap(List<Processor> processors) {
      Map<String, Processor > procMap = new HashMap<>();
      processors.forEach(processor -> procMap.put(processor.getProcessorName(), processor);
      return procMap;
   }
}

...然后您可以简单地将您的处理器映射添加到任何组件

@Service
public class MyAysncClient {

    @Autowired
    @Qualifier("processorsMap")
    private Map<String, Processor> processorsMap;  
    
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM