我正在寻找一种在 T 中注册一次泛型类 bean 的方法,以便它可以在 IoC 容器中用于 T 的所有可能值。
示例如下(我使用的是 java 17 和 org.springframework:spring-beans:6.0.11)
@Getter
@RequiredArgsConstructor
public class Item<T> {
private final T value;
}
@Component
public class A {}
@Component
public class B {}
@Configuration
@ComponentScan("my.package")
public class Config {
//the following method doesn't work
//I'm putting it here just to explain what I'm trying to achieve
@Bean
public <T> Item<T> item(T value) {
return new Item<>(value);
}
}
@SpringBootTest
@ContextConfiguration(Config.class)
class MyTest {
@Autowired
Item<A> itemA;
@Autowired
Item<B> itemB;
@Test
void myTest() {
//the test fails when loading the spring context because itemA and itemB cannot be resolved
assert itemA != null;
assert itemB != null;
}
}
我知道理论上我想要做的事情是无法实现的,因为类型擦除,但是 spring 怎么可能为 jakarta.inject.Provider 实现类似的行为呢?
以下作品:
@Component
public class A {}
@Component
public class B {}
@Configuration
@ComponentScan("my.package")
public class Config {
}
@SpringBootTest
@ContextConfiguration(Config.class)
class MyTest {
@Autowired
Provider<A> providerA;
@Autowired
Provider<B> providerB;
@Test
void myTest() {
assert providerA != null;
assert providerB != null;
}
}
就像List strings=new ArrayList();尽管被实例化为原始类型(不带泛型),但仍将正确返回字符串,以同样的方式,可以自动装配不带泛型类型的 Provider (
new Provider()
),并且一旦将其分配给 Provider,它将正确返回类型 B。然而,这与您的用例不同,您希望在 @Bean 定义中获取 T 值,但仍然没有说明它应该是哪个值。区别在于一个必须在编译时知道(T 值),而另一个(Provider 的类型)可以留到运行时)
您可以实现类似的功能,但您必须在某处定义
T value
,以便它可以自动连接到 item
Bean,或者稍微更改您的 bean 定义 - 例如以下内容将起作用:
public class Item<T> {
private T data;
public T get() {
return data;
}
}
// generics here don't play a role, could have also left them out
@Bean
public <T> Item<T> item() {
// you should still add some logic on how to set `data` based on whatever condition
return new Item<>();
}
然后将其自动装配为特定类型:
@Autowired
Item<String> item; //will correcly get autowired and return the type String