如何基于泛型自动注入实现
How to automatically inject implementation based on Generics
我有一个这样定义的服务class,
@RequiredArgsConstructor
class SomeService<T extends AbstractResponse> {
private final ValidationService<T> validationService;
....
}
我有两种 AbstractResponse
、ResponseA
和 ResponseB
,并为它们定义了验证服务。
@Service("aValidationService");
class AValidationService<ResponseA> implements ValidationService<ResponseA> {
....
}
和
@Service("ValidationService");
class BValidationService<ResponseB> implements ValidationService<ResponseB> {
....
}
现在 spring 正在抛出一个错误,因为它无法推断出要在 SomeService
中使用的 ValidationService
的实现,因为它有两个实现。如何让 spring 根据 AbstractResponse 的类型推断出正确的实现?
希望我理解您的要求。
当你有(2)个同类时,你不能自动注入。在这种情况下 ValidationService.
您可以注入 @ValidationServiceA
,或 @ValidationServiceB
,或 List<ValidationServiceI>
,然后根据您关心的 <T> type
,注入您想要的 return :
下面的解决方案强调了这一点。
方法getGenericParameter()
用于return<T>
参数。这是为了避免使用反射。
用于根据您需要的输入确定要使用哪个 ValidationService 的方法methodWhichDeterminesWhichServiceToUseBasedOnResponseType
。
您可以在下面找到完整的解决方案,包括验证测试。
import org.springframework.stereotype.Service;
@Service
public class ValidationServiceA implements ValidationServiceI<ResponseA>{
@Override public Class<ResponseA> getGenericParameter() {
return ResponseA.class;
}
public void print(){
System.out.println("Service A");
}
}
@Service
public class ValidationServiceB implements ValidationServiceI<ResponseB>{
@Override public Class<ResponseB> getGenericParameter() {
return ResponseB.class;
}
public void print(){
System.out.println("Service B");
}
}
public interface ValidationServiceI<T>{
Class<T> getGenericParameter();
void print();
}
@Service
public class ServiceWhichCallsOthers {
@Autowired
private List<ValidationServiceI> validationServices;
public <T> ValidationServiceI<T> methodWhichDeterminesWhichServiceToUseBasedOnResponseType(T responseType){
Optional<ValidationServiceI> validationServiceSupportingResponse = validationServices.stream().filter(validationServiceI -> validationServiceI.getGenericParameter().equals(responseType)).findFirst();
return validationServiceSupportingResponse.get();
}
public void callValidationServiceA(){
methodWhichDeterminesWhichServiceToUseBasedOnResponseType(ResponseA.class).print();
}
public void callValidationServiceB(){
methodWhichDeterminesWhichServiceToUseBasedOnResponseType(ResponseB.class).print();
}
}
@SpringBootTest
public class ServiceWhichCallsOthersIT {
@Autowired
private ServiceWhichCallsOthers serviceWhichCallsOthers;
@Test
public void validateBasedOnResponseType(){
Assertions.assertEquals(ValidationServiceA.class, serviceWhichCallsOthers.methodWhichDeterminesWhichServiceToUseBasedOnResponseType(ResponseA.class).getClass());
Assertions.assertEquals(ValidationServiceB.class, serviceWhichCallsOthers.methodWhichDeterminesWhichServiceToUseBasedOnResponseType(ResponseB.class).getClass());
serviceWhichCallsOthers.callValidationServiceA();
serviceWhichCallsOthers.callValidationServiceB();
}
}
我有一个这样定义的服务class,
@RequiredArgsConstructor
class SomeService<T extends AbstractResponse> {
private final ValidationService<T> validationService;
....
}
我有两种 AbstractResponse
、ResponseA
和 ResponseB
,并为它们定义了验证服务。
@Service("aValidationService");
class AValidationService<ResponseA> implements ValidationService<ResponseA> {
....
}
和
@Service("ValidationService");
class BValidationService<ResponseB> implements ValidationService<ResponseB> {
....
}
现在 spring 正在抛出一个错误,因为它无法推断出要在 SomeService
中使用的 ValidationService
的实现,因为它有两个实现。如何让 spring 根据 AbstractResponse 的类型推断出正确的实现?
希望我理解您的要求。
当你有(2)个同类时,你不能自动注入。在这种情况下 ValidationService.
您可以注入 @ValidationServiceA
,或 @ValidationServiceB
,或 List<ValidationServiceI>
,然后根据您关心的 <T> type
,注入您想要的 return :
下面的解决方案强调了这一点。
方法getGenericParameter()
用于return<T>
参数。这是为了避免使用反射。
用于根据您需要的输入确定要使用哪个 ValidationService 的方法methodWhichDeterminesWhichServiceToUseBasedOnResponseType
。
您可以在下面找到完整的解决方案,包括验证测试。
import org.springframework.stereotype.Service;
@Service
public class ValidationServiceA implements ValidationServiceI<ResponseA>{
@Override public Class<ResponseA> getGenericParameter() {
return ResponseA.class;
}
public void print(){
System.out.println("Service A");
}
}
@Service
public class ValidationServiceB implements ValidationServiceI<ResponseB>{
@Override public Class<ResponseB> getGenericParameter() {
return ResponseB.class;
}
public void print(){
System.out.println("Service B");
}
}
public interface ValidationServiceI<T>{
Class<T> getGenericParameter();
void print();
}
@Service
public class ServiceWhichCallsOthers {
@Autowired
private List<ValidationServiceI> validationServices;
public <T> ValidationServiceI<T> methodWhichDeterminesWhichServiceToUseBasedOnResponseType(T responseType){
Optional<ValidationServiceI> validationServiceSupportingResponse = validationServices.stream().filter(validationServiceI -> validationServiceI.getGenericParameter().equals(responseType)).findFirst();
return validationServiceSupportingResponse.get();
}
public void callValidationServiceA(){
methodWhichDeterminesWhichServiceToUseBasedOnResponseType(ResponseA.class).print();
}
public void callValidationServiceB(){
methodWhichDeterminesWhichServiceToUseBasedOnResponseType(ResponseB.class).print();
}
}
@SpringBootTest
public class ServiceWhichCallsOthersIT {
@Autowired
private ServiceWhichCallsOthers serviceWhichCallsOthers;
@Test
public void validateBasedOnResponseType(){
Assertions.assertEquals(ValidationServiceA.class, serviceWhichCallsOthers.methodWhichDeterminesWhichServiceToUseBasedOnResponseType(ResponseA.class).getClass());
Assertions.assertEquals(ValidationServiceB.class, serviceWhichCallsOthers.methodWhichDeterminesWhichServiceToUseBasedOnResponseType(ResponseB.class).getClass());
serviceWhichCallsOthers.callValidationServiceA();
serviceWhichCallsOthers.callValidationServiceB();
}
}