如何基于泛型自动注入实现

How to automatically inject implementation based on Generics

我有一个这样定义的服务class,

@RequiredArgsConstructor
class SomeService<T extends AbstractResponse> {
    private final ValidationService<T> validationService;
    ....
}

我有两种 AbstractResponseResponseAResponseB,并为它们定义了验证服务。

@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();

    }
}