如何在当前调用中根据 RequestParam 注入正确的 bean 实现
Posted
技术标签:
【中文标题】如何在当前调用中根据 RequestParam 注入正确的 bean 实现【英文标题】:How to inject the right bean implementation according to a RequestParam in the current call 【发布时间】:2022-01-21 07:04:10 【问题描述】:我有这个 Spring bean(这个 RestController
用于示例),根据国家/地区(比如说传入的参数),我想注入正确的实现TaxpayerNameService
.
所以,我有TaxpayerNameService
接口和两个(未来更多)需要注入控制器的当前调用 的接口实现;我说 current call 因为同一个控制器将为许多国家/地区提供服务,并且取决于我在某处发送的 iso2 常量(现在它来自documentType.getCountry()
,我必须检索 在运行时正确的TaxpayerNameService
实现并调用该方法getTaxpayerName
。
每个国家/地区都有不同的服务集,因此接口的每个实现都会正确调用正确的服务。
@RestController
@RequestMapping("/taxpayers")
public class TaxpayerController
@Autowired
@Qualifier("TaxpayerNameServiceImplHN")
private TaxpayerNameService taxpayerNameServHN;
@Autowired
@Qualifier("TaxpayerNameServiceImplCR")
private TaxpayerNameService taxpayerNameServCR;
@GetMapping(path = "/documentType-documentNumber/name", produces = MediaType.TEXT_PLAIN_VALUE)
public ResponseEntity<String> getName(
final @PathVariable("documentType") TaxpayerDocumentType documentType,
final @PathVariable("documentNumber") String documentNumber) throws NoSuchMethodException
try
final TaxpayerNameService taxpayerNameService = getTaxpayerNameServiceImpl(documentType.getCountry());
return ResponseEntity.of(taxpayerNameService.getTaxpayerName(documentType, documentNumber));
catch (IOException ex)
log.error(String.format("Error querying [%s][%s]", documentType, documentNumber), ex);
return ResponseEntity.internalServerError().build();
private TaxpayerNameService getTaxpayerNameServiceImpl(final String country)
switch(country)
case "CR":
return taxpayerNameServCR;
case "HN":
return taxpayerNameServHN;
default:
throw new IllegalArgumentException("Invalid country");
除了这种丑陋的方法getTaxpayerNameServiceImpl
之外,我想做的是一种更优雅/更灵活的方法。
【问题讨论】:
我会注入一个实现TaxPayerNameService
的 bean 列表,给该接口一个 String getCountry()
方法,然后将它们放入构造函数中的 Map
或单独的 @987654332 @豆。
还有一个小问题:当你抛出IllegalArgumentException
时,请报告错误的国家。
“优雅/弹簧方式”是在@RequestScope
中创建FactoryBean
,坏消息是您在实现org.springframework.beans.factory.FactoryBean#getObject
时需要手动解析请求uri
【参考方案1】:
使用BeanFactory
以编程方式创建 bean:
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.stereotype.Component;
@Component
public class TaxpayerNameServiceFactory implements BeanFactoryAware
private static final String BEAN_NAME_FORMAT = "TaxpayerNameServiceImpl%s";
private BeanFactory beanFactory;
public TaxpayerNameService getTaxpayerNameServiceImpl(String countryName)
try
return (TaxpayerNameService) beanFactory.getBean(String.format(BEAN_NAME_FORMAT, countryName));
catch(Exception e)
throw new TaxpayerNameServiceException(e.getMessage(), e);
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException
this.beanFactory = beanFactory;
TaxpayerNameServiceImplCR 类:
import org.springframework.stereotype.Component;
@Component("TaxpayerNameServiceImplCR")
public class TaxpayerNameServiceImplCR implements TaxpayerNameService
//All methods
休息控制器类:
@RestController
@RequestMapping("/taxpayers")
public class TaxpayerController
@Autowired
TaxpayerNameServiceFactory factory;
@GetMapping(path = "/documentType-documentNumber/name", produces = MediaType.TEXT_PLAIN_VALUE)
public ResponseEntity<String> getName(
final @PathVariable("documentType") TaxpayerDocumentType documentType,
final @PathVariable("documentNumber") String documentNumber) throws NoSuchMethodException
try
final TaxpayerNameService taxpayerNameService = factory.getTaxpayerNameServiceImpl(documentType.getCountry());
return ResponseEntity.of(taxpayerNameService.getTaxpayerName(documentType, documentNumber));
catch (IOException ex)
log.error(String.format("Error querying [%s][%s]", documentType, documentNumber), ex);
return ResponseEntity.internalServerError().build();
【讨论】:
当你抛出TaxpayerNameServiceException
时,你应该传递 e
作为原因。【参考方案2】:
或者这个?
public enum Country
HR("HR", TaxpayerNameServiceImplHR.class),
CR("CR", TaxpayerNameServiceImplCR.class);
private String code;
private Class<? extends TaxpayerNameService> serviceClass;
Country(String code, Class<? extends TaxpayerNameService> svcClass)
this.code = code;
this.serviceClass = svcClass;
public String getCode()
return code;
public Class<? extends TaxpayerNameService> getServiceClass()
return serviceClass;
public static Optional<Country> findCountry(String code)
return java.util.stream.Stream.of(Country.values())
.filter(country -> code.equals(country.getCode()))
.findFirst();
public class TaxPayerController
@Autowired
private ApplicationContext context;
public ResponseEntity<String> getName(final @PathVariable("documentType") TaxpayerDocumentType documentType,
final @PathVariable("documentNumber") String documentNumber) throws NoSuchMethodException
Optional<Country> optionalCountry = Country.findCountry(documentType.getCountry());
if (optionalCountry.isEmpty())
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
final TaxpayerNameService taxpayerNameService = context.getBean(optionalCountry.get().getServiceClass());
return ResponseEntity.ok(taxpayerNameService.getTaxpayerName(documentType, documentNumber));
【讨论】:
以上是关于如何在当前调用中根据 RequestParam 注入正确的 bean 实现的主要内容,如果未能解决你的问题,请参考以下文章