我們在項目中是有兩個Redis源,有兩個Redis Bean如下:
Bean1:dataRedisTemplate
@Bean(name = "dataRedisTemplate")
public RedisTemplate dataRedisTemplate() {
RedisTemplate template = new RedisTemplate();
template.setConnectionFactory(sessionLettuceConnectionFactory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashKeySerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}
// factory
@Resource
@Qualifier(value = "sessionLettuceConnectionFactory")
private RedisConnectionFactory sessionLettuceConnectionFactory;
// clusterNodes
@Value("${spring.session-redis.cluster.nodes}")
private String clusterNodes;
Bean2:redisTemplate
@Primary
@Bean(name = "redisTemplate")
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new StringRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
// factory
@Resource
@Qualifier(value = "lettuceConnectionFactory")
private RedisConnectionFactory lettuceConnectionFactory;
// clusterNodes
@Value("${spring.redis.cluster.nodes}")
private String clusterNodes;
我在另一個應用中把數(shù)據(jù)放入到Bean2 redisTemplate對應的Redis中,于是我在這個應用中使用方式如下:
@Autowired
private RedisTemplate dataRedisTemplate;
// 根據(jù)key獲取數(shù)據(jù)
Object obj = dataRedisTemplate.opsForValue().get(key);
最后結果是,我明明在key里面存放了數(shù)據(jù)(進入Redis客戶端通過命令確定有這個key及數(shù)據(jù)),但是我在這里就是獲取不到,obj一直為空。
一開始以為是key和value序列號的問題,通過排查確定不是這個問題。
最后發(fā)現(xiàn)Redis數(shù)據(jù)源調(diào)用不對導致的,也就是說我希望是使用dataRedisTemplate,實際上是一直在使用redisTemplate。
先說答案,我后面把@Autowired換成@Resource 注解解決了這個問題,即:
@Autowired
private RedisTemplate dataRedisTemplate;
換成》》》》
@Resource
private RedisTemplate dataRedisTemplate;
@Autowired和@Resource最大的區(qū)別就是:@Autowired 按 byType 自動注入,而 @Resource 則默認按 byName 自動注入。
這里還需要注意一個注解@Primary,官方的說明如下:
Indicates that a bean should be given preference when multiple candidates are qualified to autowire a single-valued dependency. If exactly one 'primary' bean exists among the candidates, it will be the autowired value.
@Primary 優(yōu)先方案,被注解的實現(xiàn),優(yōu)先被注入

其實我們可以自己寫一個單側來試試:
@RunWith(SpringRunner.class)
@SpringBootTest(classes=FotaOptionApplication.class)
public class TokenUtilTest {
@Resource
//@Autowired
private RedisTemplate dataRedisTemplate;
@Test
public void test(){
System.out.println(dataRedisTemplate.getClass().toString());
}
}
通常情況下@Autowired是通過byType的方法注入的,可是在多個實現(xiàn)類的時候,byType的方式不再是唯一,而需要通過byName的方式來注入,而這個name默認就是根據(jù)變量名來的。
也就是說,如果沒有在redisTemplate()上面增加@Primary的話是沒有問題的,因為有多個實現(xiàn)時,@Autowired是會通過byName的方式來注入的,但是按照上面說的,因為有了@Primary,@Autowired注解會優(yōu)先使用Bean redisTemplate。
@Primary
@Bean(name = "redisTemplate")
public RedisTemplate<String, Object> redisTemplate() {
}
解決方案可以是把@Autowired換成@Resource,如下:
@Autowired
private RedisTemplate dataRedisTemplate;
換成》》》》
@Resource
private RedisTemplate dataRedisTemplate;
也可以是增加@Qualifier(value = "dataRedisTemplate"),如下:
@Autowired
private RedisTemplate dataRedisTemplate;
換成》》》》
@Autowired
@Qualifier(value = "dataRedisTemplate")
private RedisTemplate dataRedisTemplate;
最后,祝大家都能好好看書,不要學我。