如何在当前调用中根据 RequestParam 注入正确的 bean 实现
How to inject the right bean implementation according to a RequestParam in the current call
我有这个 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
.
,我想做的是更 elegant/spring 的方法
使用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 class:
import org.springframework.stereotype.Component;
@Component("TaxpayerNameServiceImplCR")
public class TaxpayerNameServiceImplCR implements TaxpayerNameService {
//All methods
}
休息控制器class:
@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();
}
}
}
或者这个?
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));
}
}
我有这个 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
.
使用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 class:
import org.springframework.stereotype.Component;
@Component("TaxpayerNameServiceImplCR")
public class TaxpayerNameServiceImplCR implements TaxpayerNameService {
//All methods
}
休息控制器class:
@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();
}
}
}
或者这个?
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));
}
}