spring-boot筆記--緩存

六忆肾、Spring Boot與緩存

1郊艘、Spring緩存抽象

Spring定義了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口來統(tǒng)一不同的緩存技術(shù),并支持使用JCache(JSR-107)注解簡(jiǎn)化我們的開發(fā)

2级及、幾個(gè)重要概念和緩存注解

組件和注解 功能
Cache 緩存接口颖变,定義緩存操作盖高,實(shí)現(xiàn)有: RedisCache、EhCacheCache仲闽、ConcurrentMapCache 等
CacheManager 緩存管理器脑溢,管理各種緩存(Cache)組件
@Cacheable 主要對(duì)方法進(jìn)行配置,能夠根據(jù)方法的請(qǐng)求參數(shù)對(duì)其結(jié)果繼續(xù)緩存
@CacheEvict 清空緩存
@CachePut 保證方法被調(diào)用、又希望結(jié)果被緩存
@EnableCaching 開啟基于注解的緩存
keyGenerator 緩存數(shù)據(jù)時(shí)key生成策略
serialize 緩存數(shù)據(jù)時(shí)value序列化策略

3屑彻、Spring Boot緩存的使用

  1. 搭建基本環(huán)境验庙、數(shù)據(jù)庫表、javabean封裝數(shù)據(jù)

  2. 整合mybatis操作數(shù)據(jù)庫社牲,關(guān)于整合mybatis可以看之前的是Spring Boot與數(shù)據(jù)訪問

  3. 開啟基于注解的緩存

    @EnableCaching
    //開啟緩存
    @MapperScan(value = "com.cache.springboot.mapper")
    @SpringBootApplication
    public class SpringbootApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringbootApplication.class, args);
        }
    
    }
    
        //將方法的結(jié)果進(jìn)行緩存粪薛,以后再要相同的數(shù)據(jù),直接從緩存中獲取搏恤,不會(huì)調(diào)用方法
        @Cacheable(cacheNames = "share")
        public Share getShareById(Integer id){
            Share shareById = shareMapper.getShareById(id);
            return shareById;
        }
    

    我們可以查看@Cacheable里的屬性

    • cacheNames/value:指定緩存組件的名字

      關(guān)于緩存組件的名字:CacheManager管理多個(gè)Cache組件违寿,對(duì)緩存真正的CRUD操作在Cache組件中,每一個(gè)緩存組件有自己唯一一個(gè)名字

      我們可以傳入數(shù)組熟空,將數(shù)據(jù)放入多個(gè)緩存里邊

    • key:緩存數(shù)據(jù)使用的key藤巢,可以用它來指定,默認(rèn)是使用方法參數(shù)的值息罗,我們可以編寫SpELl指定

      舉例:指定key為getShare[1]掂咒、getShare[2]......

      表達(dá)式寫為key="#root.methodName+'['+#id+']'"

      名字 位置 描述 示例
      methodName root object 當(dāng)前被調(diào)用的方法名 #root.methodName
      method root object 當(dāng)前被調(diào)用的方法 #root.method.name

    | target | root object | 當(dāng)前被調(diào)用的目標(biāo)對(duì)象 | #root.target |
    | targetClass | root object | 當(dāng)前被調(diào)用的目標(biāo)對(duì)象類 | #root.targetClass |
    | args | root object | 當(dāng)前被調(diào)用方法的參數(shù)列表 | #root.args[0] |
    | caches | root object | 當(dāng)前方法調(diào)用使用的緩存列表(如@Cacheable(value{"cache1", "cache2"})),則有兩個(gè)cache | #root.caches[0].name |
    | argument name | evaluation context | 方法參數(shù)的名字迈喉,可以直接#參數(shù)名绍刮,也可以使用#p0或#a0的形式,0代表參數(shù)的索引 | #ban挨摸、#a[0]录淡、#p0如果是類可以#Share.id |
    | result | evaluation context | 方法執(zhí)行后的返回值(僅當(dāng)方法執(zhí)行后的判斷有效,如"unless"油坝,"cache put"的表達(dá)式嫉戚,"cache evict"的表達(dá)式,beforeInvocation=false),注意@Cacheable注解的方法key不能使用#result得到返回值澈圈,因?yàn)榉椒ㄐ枰谶\(yùn)行前就生成一個(gè)key | #result |

    • keyGenerator:key的生成器彬檀,可以自己指定key的生成器的組件id,默認(rèn)的key就是用一個(gè)keyGenerator生成的瞬女,key和keyGenerator二選一使用

      @Configuration
      public class MyCacheConfig {
      
          @Bean("myKeyGenerator")
          public KeyGenerator keyGenerator(){
              return new KeyGenerator(){
      
                  @Override
                  public Object generate(Object o, Method method, Object... objects) {
                      return method.getName()+"["+ Arrays.asList(objects).toString()+"]";
                  }
              };
          }
      }
      
  • cacheManager:指定緩存管理器窍帝,如redis,或者cacheResolver指定緩存解析器诽偷,二選一

  • condition:指定符合條件的情況下才緩存

    舉例:condition="#a0>1 and ......" 第一個(gè)參數(shù)的值大于一才緩存

  • unless:否定緩存坤学,當(dāng)unless指定的條件為true,方法的返回值就不會(huì)被緩存报慕,可以獲取到結(jié)果進(jìn)行判斷

  • sync:是否使用異步模式

  1. 緩存的原理

    自動(dòng)配置類:CacheAutoConfiguration

    //在CacheAutoConfiguration里有這個(gè)類的selectImports方法可以得到所有的配置類深浮,Spring Boot自動(dòng)配置緩存的時(shí)候引入了很多的配置類
    static class CacheConfigurationImportSelector implements ImportSelector {
        CacheConfigurationImportSelector() {
        }
    
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            CacheType[] types = CacheType.values();
            String[] imports = new String[types.length];
    
            for(int i = 0; i < types.length; ++i) {
                imports[i] = CacheConfigurations.getConfigurationClass(types[i]);
            }
    
            return imports;
        }
    }
    

    默認(rèn)生效的配置有SimpleCacheConfiguration

    SimpleCacheConfiguration給緩存注冊(cè)了一個(gè)cacheManager

    ConcurrentMapCacheManager的作用

    @Bean
    //SimpleCacheConfiguration給緩存注冊(cè)了一個(gè)cacheManager:ConcurrentMapCacheManager,可以獲取和創(chuàng)建ConcurrentMapCacheManager類型的緩存組件眠冈,將數(shù)據(jù)存取在ConcurrentMap中
    ConcurrentMapCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers cacheManagerCustomizers) {
        ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();
        List<String> cacheNames = cacheProperties.getCacheNames();
        if (!cacheNames.isEmpty()) {
            cacheManager.setCacheNames(cacheNames);
        }
    
        return (ConcurrentMapCacheManager)cacheManagerCustomizers.customize(cacheManager);
    }
    

    運(yùn)行的流程@Cacheable

    1. 方法運(yùn)行前飞苇,先去檢查緩存Cache(緩存組件),按照cacheNames指定的名字獲取(CacheManager先獲取相應(yīng)的緩存)布卡,第一次獲取緩存如果沒有會(huì)自動(dòng)創(chuàng)建

    2. 去Cache中查找緩存的內(nèi)容雨让,使用一個(gè)key,默認(rèn)是方法的參數(shù)忿等,key是按照某種策略生成的栖忠,策略使用keyGenerator生成,默認(rèn)使用SimpleKeyGenerator生成key

      SimpleKeyGenerator生成key的策略:

      如果沒有參數(shù)key=new SimpleKey()

      有一個(gè)參數(shù)key=參數(shù)的值

      有多個(gè)參數(shù)key=new SimpleKey(params)

    3. 沒有查到緩存就調(diào)用目標(biāo)方法

    4. 將目標(biāo)方法返回的結(jié)果放進(jìn)緩存中

    @CacheEvict

    • key:指定要清除的緩存

    • allEntries=true:指定清除這個(gè)緩存中的所有數(shù)據(jù)

    • beforeInvocation=false:緩存的清除是否在方法之前執(zhí)行

      默認(rèn)是在方法之后執(zhí)行贸街,例如方法中出現(xiàn)異常就不會(huì)清除

    @Caching

    //定義復(fù)雜的緩存規(guī)則
    @Caching(
            cacheable = {
                @Cacheable(cacheNames = "share", key="#result.id")
            },
            put = {
                @CachePut(cacheNames = "share", key="#result.tscode")
            }
    )
    

    @CacheConfig

    //定義全局的cacheconfig
    @CacheConfig(cacheNames = "share")
    

4娃闲、搭建Redis環(huán)境和整合Redis

百度Redis的安裝,十分簡(jiǎn)單

整合Redis

@Autowired
RedisTemplate redisTemplate;  //操作k-v字符串的

@Autowired
StringRedisTemplate stringRedisTemplate;  //操作k-v對(duì)象的

@Autowired
RedisTemplate<Object, Object> myredisTemplate;

@Test
public void testRedis(){
    stringRedisTemplate.opsForValue();  //操作String字符串
    stringRedisTemplate.opsForList();  //操作list列表
    stringRedisTemplate.opsForSet();  //操作set集合
    stringRedisTemplate.opsForHash();  //操作Hash散列
    stringRedisTemplate.opsForZSet();  //操作ZSet有序集合

    //默認(rèn)保存對(duì)象匾浪,會(huì)使用JDK的序列化機(jī)制皇帮,序列化后的數(shù)據(jù)保存在Redis中
    //如果我們想用json格式保存數(shù)據(jù),可以自己配置相應(yīng)的Config蛋辈,如下面的MyRedisConfig類
    redisTemplate.opsForValue();  //與上述類似属拾,不過可以存入對(duì)象
    myredisTemplate.opsForValue().set("ceshi", shareMapper.getShareById(1));
    System.out.println(myredisTemplate.opsForValue().get("ceshi"));
}

自己的RedisConfig

@Configuration
public class MyRedisConfig {

    @Bean
    public RedisTemplate<Object, Object> myredisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        template.setDefaultSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class));
        return template;
    }

}

注意如果在Redis命令行查詢,先通過keys *命令查看所有key冷溶,可以看到Redis中的key為"\"ceshi\""渐白,所以直接get ceshi是無法查到的

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市逞频,隨后出現(xiàn)的幾起案子纯衍,更是在濱河造成了極大的恐慌,老刑警劉巖苗胀,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件襟诸,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡基协,警方通過查閱死者的電腦和手機(jī)歌亲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來澜驮,“玉大人陷揪,你說我怎么就攤上這事≡忧睿” “怎么了悍缠?”我有些...
    開封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長耐量。 經(jīng)常有香客問我飞蚓,道長,這世上最難降的妖魔是什么拴鸵? 我笑而不...
    開封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任玷坠,我火速辦了婚禮,結(jié)果婚禮上劲藐,老公的妹妹穿的比我還像新娘八堡。我一直安慰自己,他們只是感情好聘芜,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開白布兄渺。 她就那樣靜靜地躺著,像睡著了一般汰现。 火紅的嫁衣襯著肌膚如雪挂谍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天瞎饲,我揣著相機(jī)與錄音口叙,去河邊找鬼。 笑死嗅战,一個(gè)胖子當(dāng)著我的面吹牛妄田,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播驮捍,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼疟呐,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了东且?” 一聲冷哼從身側(cè)響起启具,我...
    開封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎珊泳,沒想到半個(gè)月后鲁冯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡色查,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年晓褪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片综慎。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡涣仿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出示惊,到底是詐尸還是另有隱情好港,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布米罚,位于F島的核電站钧汹,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏录择。R本人自食惡果不足惜拔莱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一碗降、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧塘秦,春花似錦讼渊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至须误,卻和暖如春挨稿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背京痢。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來泰國打工奶甘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人祭椰。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓甩十,卻偏偏與公主長得像,于是被迫代替她去往敵國和親吭产。 傳聞我的和親對(duì)象是個(gè)殘疾皇子侣监,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容