1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Spring Boot集成Redis,這個坑把我害慘了!

        共 3337字,需瀏覽 7分鐘

         ·

        2020-12-29 14:31

        最近項目中使用SpringBoot集成Redis,踩到了一個坑:從Redis中獲取數(shù)據(jù)為null,但實際上Redis中是存在對應(yīng)的數(shù)據(jù)的。是什么原因?qū)е麓丝拥哪兀?/span>

        本文就帶大家從SpringBoot集成Redis、所踩的坑以及自動配置源碼分析來學(xué)習(xí)一下SpringBoot中如何正確的使用Redis。

        SpringBoot集成Redis

        在SpringBoot項目中只需在pom文件中引入Redis對應(yīng)的starter,配置Redis連接信息即可進行使用了。pom依賴引入:


        ????org.springframework.boot
        ????spring-boot-starter-data-redis

        對應(yīng)application配置文件配置:

        spring:
        ??redis:
        ????host:?127.0.0.1
        ????port:?6379
        ????database:?1
        ????password:?123456
        ????timeout:?5000

        通過以上兩項配置即完成了Redis的集成,下面便是具體的使用,這里以單元測試的形式呈現(xiàn)。

        @SpringBootTest
        @RunWith(SpringRunner.class)
        public?class?TokenTest?{

        ????@Autowired
        ????private?RedisTemplate?redisTemplate;

        ????@Test
        ????public?void?getValue()?{
        ????????Object?value?=?redisTemplate.opsForValue().get("1");
        ????????System.out.println("value:"?+?value);
        ????}
        }

        可以看到直接通過@Autowired注入RedisTemplate之后,即可調(diào)用RedisTemplate提供的方法操作。RedisTemplate提供了豐富的Redis操作方法,具體使用查看相應(yīng)的API即可,這里不再拓展。

        項目中遇到的坑

        回歸到最開始的問題:從Redis中獲取數(shù)據(jù)為null,但實際上Redis中是存在對應(yīng)的數(shù)據(jù)的。

        其實問題表象很詭異,但問題的原因很簡單,就是Redis中存數(shù)據(jù)和取數(shù)據(jù)時采用了不同的RedisTemplate導(dǎo)致的。

        在SpringBoot中,針對Redis的自動配置類默認會初始化兩個RedisTemplate,先來看一下RedisAutoConfiguration中源碼:

        @Configuration
        @ConditionalOnClass({RedisOperations.class})
        @EnableConfigurationProperties({RedisProperties.class})
        @Import({LettuceConnectionConfiguration.class,?JedisConnectionConfiguration.class})
        public?class?RedisAutoConfiguration?{

        ????@Bean
        ????@ConditionalOnMissingBean(
        ????????name?=?{"redisTemplate"}
        ????)
        ????public?RedisTemplate?redisTemplate(RedisConnectionFactory?redisConnectionFactory)?throws?UnknownHostException?{
        ????????RedisTemplate?template?=?new?RedisTemplate();
        ????????template.setConnectionFactory(redisConnectionFactory);
        ????????return?template;
        ????}

        ????@Bean
        ????@ConditionalOnMissingBean
        ????public?StringRedisTemplate?stringRedisTemplate(RedisConnectionFactory?redisConnectionFactory)?throws?UnknownHostException?{
        ????????StringRedisTemplate?template?=?new?StringRedisTemplate();
        ????????template.setConnectionFactory(redisConnectionFactory);
        ????????return?template;
        ????}
        }

        可以看到RedisAutoConfiguration中初始化了兩個RedisTemplate的bean。第一個Bean類型為RedisTemplate,Bean的名稱為redisTemplate,而且是當容器中不存在對應(yīng)的Bean name時才會進行初始化。第二Bean類型為StringRedisTemplate,Bean的名稱為stringRedisTemplate,該類繼承自RedisTemplate。

        也就說一個Bean是針對Object對象處理的,一個是針對String對象進行處理的。

        導(dǎo)致出現(xiàn)坑的原因便是set時注入的是RedisTemplate,而獲取時注入的是StringRedisTemplate。這么明顯的錯誤應(yīng)該很容易排查的???

        問題為什么隱藏的那么深?

        如果直接是因為兩處類型不一致導(dǎo)致的,的確很好排查,看一下注入的RedisTemplate即可。

        但問題難以排查,還因為另外一個因素:@Resource和@Autowired注入的問題。

        默認情況下@Resource采用先根據(jù)bean名稱注入,找不到再根據(jù)類型注入,而@Autowired默認采用根據(jù)類型注入。項目獲取數(shù)據(jù)時采用了@Resource注入方式,如下:

        @Resource
        private?RedisTemplate?redisTemplate;

        而存儲時采用的是@Autowired注入的:

        @Autowired
        private?RedisTemplate?redisTemplate;

        上面兩種形式的注入,在只存在單個實例時好像并不是什么問題,要么其中一個直接報錯,要么注入成功。但當像上述場景,出現(xiàn)了兩個RedisTemplate時,問題就變得隱蔽了。

        當采用@Autowired時,根據(jù)類型注入,直接注入了RedisTemplate的bean,因為它們的類型都是String的。

        而當使用@Resource注入時,默認采用的是根據(jù)名稱匹配,源碼中可以看到redisTemplate對應(yīng)的類型為RedisTemplate。因此,兩處注入了不同的RedisTemplate,于是就導(dǎo)致了獲取時獲取不到值的問題。

        解決方案

        找到問題的根源之后,解決問題便容易多了。

        方案一,將@Resource的注入改為@Autowired。

        方案二:將@Resource注入的bean名稱由redisTemplate改為stringRedisTemplate。當然根據(jù)具體業(yè)務(wù)場景還有其他解決方案。

        小結(jié)

        關(guān)于SpringBoot集成Redis其實很簡單,SpringBoot已經(jīng)幫我們做了大多數(shù)的事情,但因為默認初始化了兩個RedisTemplate,再加上@Autowired和@Resource注解的區(qū)別就導(dǎo)致了問題的復(fù)雜度。因此,在使用的過程中盡量保持各處采用一致的規(guī)范,阿里Java開發(fā)手冊推薦使用@Resource注解。同時,當然少不了對源碼、注解等的使用的深入學(xué)習(xí)和了解。



        往期推薦

        文件寫入的6種方法,這種方法性能最好


        線程池的7種創(chuàng)建方式,強烈推薦你用它...


        求求你,別再用wait和notify了!


        關(guān)注我,每天陪你進步一點點!

        瀏覽 52
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            美女1区2区3区 | 国产传媒在线观看 | 亚洲激情视频小说 | 日韩成人片在线 | 害羞草研究所 | 男同桌脱我内裤往里灌水小说 | Avove无套劲爆刺激在线 | 国产一级不卡在线 | 女生玩男生鸡鸡 | 亚洲青草视频 |