在自动装配一个RedisTemplate对象时,我时常有疑惑用到的究竟是spring自带的还是我们自定义的。
@Autowired
private RedisTemplate redisTemplate;
上面的redisTemplate实际上是RedisAutoConfiguration类中通过redisTempate这个bean自动装载的。
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
由于该类中还定义了stringRedisTemplate的bean,所以下面的自动装配得到的就是该bean
@Autowired
private RedisTemplate stringRedisTemplate;
注意:句柄必须是stringRedisTemplate,这个句柄对应的是bean的名字。
但是只是通过句柄来确定用的是哪个bean,未免有点不太严谨,因为在我有限的认知中,句柄只是句柄而已,改成其他字符串它还是一个句柄。但是你会发现改了句柄之后就会报错了。
有两种方式可以解决:
1,使用@Qualifier注解
2,将RedisTemplate泛型定义完整,此时句柄可以随便修改
@Autowired
private RedisTemplate<String, String> whichRedisTemplate;
可以得出结论:究竟用的是哪个bean,可以由下面3步来确定
1,@Qualifer注解中标明的bean名字
2,定义的泛型
3,句柄名字
注意:上面3步是由优先顺序的。
如果有好奇下面的定义是用的哪个bean的,可以直接给出答案,是RedisAutoConfiguration类中的redisTempate。
@Autowired
private RedisTemplate<Object,Object> stringRedisTemplate;
首先我们是不能定义相同的bean名字的。因为已经有了RedisAutoConfiguration类中定义的两个bean,也就是说我们不能再定义名称为redisTemplate或stringRedisTemplate的bean,不然会抛出BeanDefinitionOverrideException
有自定义bean时确定用到的时哪个bean的方法还是前面3步。值得注意的是第2和第3步的定义是可能会产生歧义的。现在自定义下面的bean,注意bean名字和valueSerializer和spring定义的stringRedisTemplate是不一样的
@Bean
public RedisTemplate<String, String> stringRedisTemplate_1(LettuceConnectionFactory connectionFactory) {
RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Map.class));
redisTemplate.setConnectionFactory(connectionFactory);
return redisTemplate;
}
那么下面的定义是用的哪个对象呢
@Autowired
private RedisTemplate<String,String> stringRedisTemplate;
答案是spring自定的stringRedisTemplate,那么如果将上面的句柄改成stringRedisTemplate_2,结果就是会报错,因为spring无法确定,所以会抛出NoUniqueBeanDefinitionException。
也就是说想要确定我们定义的自动装载对象就是我们想要的对象时,最好是泛型和句柄都和定义bean时保持一致。