JAVA|Spring注解踩坑記錄,涉及到的注解包括@Autowired、@Resource、@Primary、@Qualifier

我們在項目中是有兩個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)先被注入

@Primary

其實我們可以自己寫一個單側來試試:

@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;

最后,祝大家都能好好看書,不要學我。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容