我正在编写一个获取输入的服务,基于该输入我需要调用某个服务的某些隐式实现。此输入是需要调用的impls名称的列表。
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()
....
}
}
}
答案 0 :(得分:2)
是的,您可以-spring默认情况下启用此功能。即,您可以定义将Map<String, Processor>
注入到spring bean中。
这将指示spring查找作为Processor
接口实现的所有bean,这些将是map的值,相应的键将是bean名称。
因此问题中显示的代码应该可以工作。
检查著名的@Autowired注释的文档。
在“自动装配数组,集合和映射”部分中,其内容如下:
对于数组,Collection或Map依赖项类型,容器将自动装配与声明的值类型匹配的所有bean。为此,映射键必须声明为String类型,它将解析为相应的bean名称。将根据目标组件的Ordered和@Order值对容器提供的此类集合进行排序,否则将遵循其在容器中的注册顺序。另外,单个匹配的目标bean也可以是一般类型的Collection或Map本身,就这样注入。
请参见This example-其中的相关部分是将地图注入到测试中的地方。
答案 1 :(得分:1)
更好且优雅的方法是
使用以下代码定义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");
}
}
希望您的问题得到解决方案的解决
答案 2 :(得分:1)
您可以只使用getBeansOfType(Processor.class):
返回具有匹配bean的Map,其中包含bean名称作为键,并包含对应的bean实例作为值
isKeyExists(keyStore)
答案 3 :(得分:0)
我认为这对您有帮助,将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的名称(根据您的示例),那么定义一个list,spring将在同一接口上注入所有定义为服务的bean
@Autowired
private List<Processor> processors; // include all defined beans
之后,对它们中的每一个进行迭代并调用execute方法。
答案 4 :(得分:0)
是的,可以,但是需要对当前代码进行一些改进才能使其以这种方式工作。
首先,您必须向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;
}