[英]Spring Inject Generic Type
假設我們有這樣一個界面:
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可以提供一些東西來幫助我! 歡迎一些魔術!
答案很簡單:你不需要任何魔法,它只適用於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>
,並且您沒有計划擁有更多 - 其他人可能會進入並添加它們,或許多其他方案。
這里是您的模塊(應用程序和核心)之間的關系:
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;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.