Java中如何在泛型RedisTemplate Bean中获取泛型T的实际类型?
问题
我定义了一个泛型的Spring Bean方法,用于创建RedisTemplate:
@Bean(name = "redisZSetTemplate") <T> RedisTemplate<String, T> redisTemplateZSet(RedisConnectionFactory redisConnectionFactory) { }
想要获取泛型参数T的实际类型(如T.getClass()或T.class),用于Redis数据的反序列化。尝试过用TypeReference<T>和反射获取泛型父类的方式,但都无法拿到T的实际类型。目前只能为每种类型(Object、Integer、Long、ArticleZSet等)单独定义RedisTemplate Bean,代码冗余,希望实现通用的RedisTemplate Bean来复用代码。
解决方案
Java的泛型擦除机制会导致方法级的泛型参数
1. 使用类级泛型配置类
将泛型定义在类级别,通过显式指定类型的方式让Spring获取实际类型:
public class RedisZSetTemplateConfig<T> { @Bean public RedisTemplate<String, T> redisZSetTemplate(RedisConnectionFactory connectionFactory, Class<T> type) { RedisTemplate<String, T> template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); // 配置序列化器,基于传入的type处理反序列化 GenericJackson2JsonRedisSerializer valueSerializer = new GenericJackson2JsonRedisSerializer(); ObjectMapper objectMapper = valueSerializer.getObjectMapper(); // 开启类型信息,确保反序列化时能识别具体类型 objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(valueSerializer); template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(valueSerializer); template.afterPropertiesSet(); return template; } }
在应用配置中注册具体类型的Bean:
@Configuration public class AppConfig { @Bean(name = "articleZSetTemplate") public RedisTemplate<String, ArticleZSet> articleZSetTemplate(RedisConnectionFactory connectionFactory) { return new RedisZSetTemplateConfig<ArticleZSet>().redisZSetTemplate(connectionFactory, ArticleZSet.class); } // 其他类型的RedisTemplate可按同样方式注册 @Bean(name = "integerZSetTemplate") public RedisTemplate<String, Integer> integerZSetTemplate(RedisConnectionFactory connectionFactory) { return new RedisZSetTemplateConfig<Integer>().redisZSetTemplate(connectionFactory, Integer.class); } }
2. 注入TypeReference作为Bean参数
在配置方法中接收TypeReference<T>参数,注入时传入具体的匿名子类来保留泛型信息:
@Configuration public class RedisConfig { public <T> RedisTemplate<String, T> createRedisZSetTemplate(RedisConnectionFactory connectionFactory, TypeReference<T> typeRef) { RedisTemplate<String, T> template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); // 获取实际泛型类型 Type actualType = typeRef.getType(); GenericJackson2JsonRedisSerializer valueSerializer = new GenericJackson2JsonRedisSerializer(); ObjectMapper objectMapper = valueSerializer.getObjectMapper(); // 配置ObjectMapper以支持复杂类型反序列化 objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(valueSerializer); template.setDefaultSerializer(valueSerializer); template.afterPropertiesSet(); return template; } }
在需要使用的地方创建具体类型的RedisTemplate:
@Service public class ArticleService { private final RedisTemplate<String, ArticleZSet> articleZSetTemplate; public ArticleService(RedisConnectionFactory connectionFactory) { this.articleZSetTemplate = new RedisConfig().createRedisZSetTemplate( connectionFactory, new TypeReference<ArticleZSet>() {} ); } // 或者通过@Bean注册到Spring容器 @Bean(name = "articleZSetTemplate") public RedisTemplate<String, ArticleZSet> articleZSetTemplate(RedisConnectionFactory connectionFactory) { return new RedisConfig().createRedisZSetTemplate(connectionFactory, new TypeReference<ArticleZSet>() {}); } }
为什么之前的方法无效
- 泛型擦除:方法级的
<T>在编译后会被替换为Object,运行时无法获取实际类型。 new TypeReference<T>(){}:在泛型方法中创建的这个匿名类,其泛型信息是擦除后的Object,而非调用时的实际类型。只有在具体类型的匿名子类(如new TypeReference<ArticleZSet>() {})中,泛型信息才会被保留。
内容的提问来源于stack exchange,提问作者Dolphin
相关产品推荐
相关产品推荐

