弹簧注入通用类型

假设我们有这样一个界面:


public interface Validator<T> {

  boolean isValid(T data);

}

这是核心模块的一部分。多个应用程序可以使用相同的核心模块,通用 T 具有不同的值。一个示例实现是(来自应用程序的特定模块):


@Component

public class AppValidator implements Validator<String> {

  @Override

  public boolean isValid(String data) {

    return false;

  }

}

然后在控制器中(它是核心模块的一部分):


@RestController

public class ValidateController {

  @Autowired

  private Validator validator;


  @RequestMapping("/")

  public void index() {

    validator.validate("");

  }

}

IntelliJ 抱怨我使用的是原始类型;如您所见,我实际上是在控制器中这样做的。


我的问题:有没有办法以有界的方式注入依赖项(而不是注入Validator,注入Validator<String>)?但当然,绑定类型可能会根据使用核心模块的应用程序而改变?


如果不可能(可能是由于类型擦除),最好的做法是什么?只是为了使用吗Object?有没有更好的替代方案仍然提供类型安全?


我在某个地方看到有人说可以在编译时做一些魔术来改变类型,但我不确定如何,或者即使我读对了?


我正在使用 Spring,所以我希望 Spring 可以在这里提供一些帮助!欢迎施展魔法


牧羊人nacy
浏览 150回答 2
2回答

一只名叫tom的猫

答案很简单:您不需要任何魔法,它只在 Spring 中起作用。你有你的AppValidator,然后你就做(它是通过查看泛型类型注入的):@Autowired&nbsp;private Validator<String> appValidator;好吧,现在假设你有两个Validator<String>,然后呢?required a single bean but found two exception- 就是这样。这就是为什么这是一种可怕的做法,永远不要这样做。在我的工作中,一个人创建了具有 3 个泛型类型的泛型接口,然后基于这些泛型类型进行注入,人们仍然讨厌他。它看起来像这样,是的,只要您在多个实现中没有以完全相同的顺序使用完全相同的 3 个泛型类型,它就可以工作:@Autowiredprivate Invoker<String, Integer, Person> personInvoker;@Autowiredprivate Invoker<Integer, String, Animal> animalInvoker;即使您的代码中没有多个Validator<String>,并且您不打算拥有更多 - 其他人可能会进来并添加它们,或者在许多其他情况下。

慕哥9229398

这里是您的模块(应用程序和核心)之间的关系:Application 1&nbsp; &nbsp; &nbsp; &nbsp;Application 2&nbsp; &nbsp; &nbsp; Application 3&nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|Validator<Foo>&nbsp; &nbsp; &nbsp;Validator<Bar>&nbsp; &nbsp; &nbsp;Validator<FooBar>&nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;|__ __ __ __ __ __ _| __ __ __ __ __ __ |&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| <<uses>>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \ /&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Core Module&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ValidateController&nbsp; (not generic rest controller)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;这里有些不对劲,因为您希望共享组件ValidateController依赖于特定的应用程序泛型Validator类而 ValidateController不是泛型类,因此您只能坚持使用Object该Validator字段的泛型类型。为了使事情保持一致,您应该创建这个缺失的链接。事实上,您需要不同的控制器子类,因为每个控制器都需要使用特定的验证器实例。例如,您可以ValidateController在共享/代码模块中定义一个抽象类/接口,并让每个子类扩展它并为自己定义Validator要使用的通用类。这里是你的模块之间的目标关系:Application 1&nbsp; &nbsp; &nbsp; &nbsp; Application 2&nbsp; &nbsp; &nbsp; &nbsp; Application 3&nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |Validator<Foo>&nbsp; &nbsp; &nbsp; &nbsp;Validator<Bar>&nbsp; &nbsp; &nbsp; &nbsp;Validator<FooBar>FooController(bean)&nbsp; BarController(bean)&nbsp; FooBarController(bean)&nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;|__ __ __ __ __ ___ | __ ___ __ __ __ __ __|&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| <<uses>>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \ /&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Core Module&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ValidateController<T>&nbsp; (abstract class and not a bean)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;例如在核心/共享模块中:public abstract class ValidateController<T> {&nbsp; private Validator<T> validator;&nbsp; ValidateController(Validator<T> validator){&nbsp; &nbsp; &nbsp;this.validator = validator;&nbsp; }&nbsp; @RequestMapping("/")&nbsp; public void index(T t) {&nbsp; &nbsp; boolean isValid = validator.validate(t);&nbsp; }}在应用程序中,定义您的验证器实现:@Componentpublic class AppValidator implements Validator<String> {&nbsp; @Override&nbsp; public boolean validate(String data) {&nbsp; &nbsp; return ...;&nbsp; }}并定义StringController子类(或@Bean作为替代)以设置正确的Validator:@RestControllerpublic class StringController extends ValidateController<String>{&nbsp; &nbsp;public ValidateControllerApp(Validator<String> validator){&nbsp; &nbsp; &nbsp; &nbsp;this.validator = validator;&nbsp; &nbsp;}}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java