为了账号安全,请及时绑定邮箱和手机立即绑定

弹簧注入通用类型

弹簧注入通用类型

牧羊人nacy 2023-02-23 15:57:46
假设我们有这样一个界面:public interface Validator<T> {  boolean isValid(T data);}这是核心模块的一部分。多个应用程序可以使用相同的核心模块,通用 T 具有不同的值。一个示例实现是(来自应用程序的特定模块):@Componentpublic class AppValidator implements Validator<String> {  @Override  public boolean isValid(String data) {    return false;  }}然后在控制器中(它是核心模块的一部分):@RestControllerpublic class ValidateController {  @Autowired  private Validator validator;  @RequestMapping("/")  public void index() {    validator.validate("");  }}IntelliJ 抱怨我使用的是原始类型;如您所见,我实际上是在控制器中这样做的。我的问题:有没有办法以有界的方式注入依赖项(而不是注入Validator,注入Validator<String>)?但当然,绑定类型可能会根据使用核心模块的应用程序而改变?如果不可能(可能是由于类型擦除),最好的做法是什么?只是为了使用吗Object?有没有更好的替代方案仍然提供类型安全?我在某个地方看到有人说可以在编译时做一些魔术来改变类型,但我不确定如何,或者即使我读对了?我正在使用 Spring,所以我希望 Spring 可以在这里提供一些帮助!欢迎施展魔法
查看完整描述

2 回答

?
一只名叫tom的猫

TA贡献1906条经验 获得超3个赞

答案很简单:您不需要任何魔法,它只在 Spring 中起作用。你有你的AppValidator,然后你就做(它是通过查看泛型类型注入的):


@Autowired 

private Validator<String> appValidator;

好吧,现在假设你有两个Validator<String>,然后呢?required a single bean but found two exception- 就是这样。这就是为什么这是一种可怕的做法,永远不要这样做。


在我的工作中,一个人创建了具有 3 个泛型类型的泛型接口,然后基于这些泛型类型进行注入,人们仍然讨厌他。它看起来像这样,是的,只要您在多个实现中没有以完全相同的顺序使用完全相同的 3 个泛型类型,它就可以工作:


@Autowired

private Invoker<String, Integer, Person> personInvoker;


@Autowired

private Invoker<Integer, String, Animal> animalInvoker;

即使您的代码中没有多个Validator<String>,并且您不打算拥有更多 - 其他人可能会进来并添加它们,或者在许多其他情况下。


查看完整回答
反对 回复 2023-02-23
?
慕哥9229398

TA贡献1877条经验 获得超6个赞

这里是您的模块(应用程序和核心)之间的关系:


Application 1       Application 2      Application 3

     |                   |                   |

Validator<Foo>     Validator<Bar>     Validator<FooBar>

     |                   |                   |  

     |                   |                   |  

     |__ __ __ __ __ __ _| __ __ __ __ __ __ | 

                         |

                         | <<uses>>

                         |

                        \ /

                     Core Module    

                         |

                 ValidateController  (not generic rest controller)                   

这里有些不对劲,因为您希望共享组件ValidateController依赖于特定的应用程序泛型Validator类而 ValidateController不是泛型类,因此您只能坚持使用Object该Validator字段的泛型类型。

为了使事情保持一致,您应该创建这个缺失的链接。事实上,您需要不同的控制器子类,因为每个控制器都需要使用特定的验证器实例。

例如,您可以ValidateController在共享/代码模块中定义一个抽象类/接口,并让每个子类扩展它并为自己定义Validator要使用的通用类。


这里是你的模块之间的目标关系:


Application 1        Application 2        Application 3

     |                   |                      |

Validator<Foo>       Validator<Bar>       Validator<FooBar>

FooController(bean)  BarController(bean)  FooBarController(bean)

     |                   |                      |  

     |                   |                      |  

     |__ __ __ __ __ ___ | __ ___ __ __ __ __ __| 

                         |

                         | <<uses>>

                         |

                        \ /

                     Core Module    

                         |

                 ValidateController<T>  (abstract class and not a bean)                   

例如在核心/共享模块中:


public abstract class ValidateController<T> {


  private Validator<T> validator;


  ValidateController(Validator<T> validator){

     this.validator = validator;

  }


  @RequestMapping("/")

  public void index(T t) {

    boolean isValid = validator.validate(t);

  }


}

在应用程序中,定义您的验证器实现:


@Component

public class AppValidator implements Validator<String> {

  @Override

  public boolean validate(String data) {

    return ...;

  }

}

并定义StringController子类(或@Bean作为替代)以设置正确的Validator:


@RestController

public class StringController extends ValidateController<String>{


   public ValidateControllerApp(Validator<String> validator){

       this.validator = validator;

   }


}


查看完整回答
反对 回复 2023-02-23
  • 2 回答
  • 0 关注
  • 149 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号