亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > Java > 正文

淺談Spring boot cache使用和原理

2024-07-14 08:42:16
字體:
來源:轉載
供稿:網友

緩存要解決的問題:一個程序的瓶頸在于數據庫,我們也知道內存的速度是大大快于硬盤的速度的。當我們需要重復地獲取相同的數據的時候,我們一次又一次的請求數據庫或者遠程服務,導致大量的時間耗費在數據庫查詢或者遠程方法調用上,導致程序性能的惡化,這便是數據緩存要解決的問題。

類似的緩存技術有:Redis、EhCache、Guava等,現在一般常用的為Redis。

Spring 3.1 引入了激動人心的基于注釋(annotation)的緩存(cache)技術,它本質上不是一個具體的緩存實現方案(例如EHCache 或者 OSCache),而是一個對緩存使用的抽象,通過在既有代碼中添加少量它定義的各種 annotation,即能夠達到緩存方法的返回對象的效果。 

Spring 的緩存技術還具備相當的靈活性,不僅能夠使用 SpEL(Spring Expression Language)來定義緩存的 key 和各種 condition,還提供開箱即用的緩存臨時存儲方案,也支持和主流的專業緩存例如 EHCache 集成。 

其特點總結如下: 

1. 通過少量的配置 annotation 注釋即可使得既有代碼支持緩存 
2. 支持開箱即用 Out-Of-The-Box,即不用安裝和部署額外第三方組件即可使用緩存 
3. 支持 Spring Express Language,能使用對象的任何屬性或者方法來定義緩存的 key 和 condition 
4. 支持 AspectJ,并通過其實現任何方法的緩存支持 
5. 支持自定義 key 和自定義緩存管理者,具有相當的靈活性和擴展性

一、Spring boot cache原理

第一步、自動配置類;

自動啟動類:CacheAutoConfiguration

屬性配置:CacheProperties

主啟動類添加:@EnableCaching注解

cache POM添加:

<dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-cache</artifactId></dependency>

第二步、從緩存的配置類 中獲取 多個cache

CacheConfigurationImportSelector.selectImports()方法獲取

static class CacheConfigurationImportSelector implements ImportSelector {?    @Override    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;    }?}

獲取結果:SimpleCacheConfiguration 默認cache

 org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration  org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration  org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration  org.springframework.boot.autoconfigure.cache.HazelcastCacheConfiguration  org.springframework.boot.autoconfigure.cache.InfinispanCacheConfiguration  org.springframework.boot.autoconfigure.cache.CouchbaseCacheConfiguration  org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration  org.springframework.boot.autoconfigure.cache.CaffeineCacheConfiguration  org.springframework.boot.autoconfigure.cache.GuavaCacheConfiguration  org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration【默認】  org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration

第三步:SimpleCacheConfiguration.cacheManager()

此方法中給容器中注冊了一個CacheManager組件:類型為ConcurrentMapCacheManager

@Beanpublic ConcurrentMapCacheManager cacheManager() {  ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();  List<String> cacheNames = this.cacheProperties.getCacheNames();  if (!cacheNames.isEmpty()) {   cacheManager.setCacheNames(cacheNames);  }  return this.customizerInvoker.customize(cacheManager);}

第四步:查看獲取緩存方法getCache()

ConcurrentMapCacheManager 類里,數據都存儲到為ConcurrentMap 中

public Cache getCache(String name) {  Cache cache = this.cacheMap.get(name); //cacheMap 為ConcurrentMap 類型,獲取一個cache組件  if (cache == null && this.dynamic) {   synchronized (this.cacheMap) {     cache = this.cacheMap.get(name); //cahceMap不為空獲取     if (cache == null) {      //可以獲取或者創建ConcurrentMapCache類型的緩存組件;他的作用將數據保存在ConcurrentMap中;      cache = createConcurrentMapCache(name);        this.cacheMap.put(name, cache); //ConcurrentMapCache.lookup();     }   }  }  return cache;}

二、Cacheable運行流程:

? @Cacheable: 1、方法運行之前,先去查詢Cache(緩存組件),按照cacheNames指定的名字獲取; (CacheManager先獲取相應的緩存),第一次獲取緩存如果沒有Cache組件會自動創建。 2、去Cache中查找緩存的內容(ConcurrentMapCache.lookup()方法中去查找),使用一個key,默認就是方法的參數; key是按照某種策略生成的;默認是使用keyGenerator生成的,默認使用SimpleKeyGenerator生成key; SimpleKeyGenerator生成key的默認策略; 如果沒有參數;key=new SimpleKey(); 如果有一個參數:key=參數的值 如果有多個參數:key=new SimpleKey(params);

 //這個方法 SimpleKeyGenerator.generateKey()  方法生成keypublic static Object generateKey(Object... params) {  if (params.length == 0) {   return SimpleKey.EMPTY;  }  if (params.length == 1) { //如果只有一個參數,直接返回這個參數為key   Object param = params[0];   if (param != null && !param.getClass().isArray()) {     return param;   }  }  return new SimpleKey(params);}

3、沒有查到緩存就調用目標方法; 4、將目標方法返回的結果,放進緩存中ConcurrentMapCache.put();

@Cacheable標注的方法執行之前先來檢查緩存中有沒有這個數據,默認按照參數的值作為key去查詢緩存, 如果沒有就運行方法并將結果放入緩存;以后再來調用就可以直接使用緩存中的數據;

? 核心: 1)、使用CacheManager【ConcurrentMapCacheManager】按照名字得到Cache【ConcurrentMapCache】組件 2)、key使用keyGenerator生成的,默認是SimpleKeyGenerator

詳細執行流程:ConcurrentMapCache.lookup()上斷點查看,執行過程

//第一步CacheAspectSupport 中execute()private Object execute(final CacheOperationInvoker invoker, Method method, CacheOperationContexts contexts) //第二步 CacheAspectSupportprivate Cache.ValueWrapper findCachedItem(Collection<CacheOperationContext> contexts) {  Object result = CacheOperationExpressionEvaluator.NO_RESULT;  for (CacheOperationContext context : contexts) {    if (isConditionPassing(context, result)) {      Object key = generateKey(context, result); //獲取key      Cache.ValueWrapper cached = findInCaches(context, key);      if (cached != null) {        return cached;      }      else {        if (logger.isTraceEnabled()) {          logger.trace("No cache entry for key '" + key + "' in cache(s) " + context.getCacheNames());        }      }    }  }  return null;}//第三步:CacheAspectSupport.findInCaches()//第四步:AbstractCacheInvoker.doGet()//第五步:AbstractValueAdaptingCache.get();@Overridepublic ValueWrapper get(Object key) {    Object value = lookup(key);    return toValueWrapper(value);}// 第六步:ConcurrentMapCache.lookup(); 從ConcurrentMap 中根據key獲取值@Overrideprotected Object lookup(Object key) {    return this.store.get(key);}

三、Cacheable 注解的幾個屬性:

1、cacheNames/value:指定緩存組件的名字;將方法的返回結果放在哪個緩存中,是數組的方式,可以指定 多個緩存;

2、key:緩存數據使用的key;可以用它來指定。默認是使用方法參數的值 1-方法的返回值

? 編寫SpEL; #i d;參數id的值 #a0 #p0 #root.args[0]

? getEmp[2]

3、keyGenerator:key的生成器;可以自己指定key的生成器的組件id

? key/keyGenerator:二選一使用;

4、cacheManager:指定緩存管理器;或者cacheResolver指定獲取解析器

5、condition:指定符合條件的情況下才緩存;

? ,condition = "#id>0"

? condition = "#a0>1":第一個參數的值》1的時候才進行緩存

6、unless:否定緩存;當unless指定的條件為true,方法的返回值就不會被緩存;可以獲取到結果進行判斷

? unless = "#result == null"

? unless = "#a0==2":如果第一個參數的值是2,結果不緩存;

7、sync:是否使用異步模式;異步模式的情況下unless不支持

四、Cache使用:

1.Cacheable的使用

@Cacheable(value = {"emp"}/*,keyGenerator = "myKeyGenerator",condition = "#a0>1",unless = "#a0==2"*/)public Employee getEmp(Integer id){  System.out.println("查詢"+id+"號員工");  Employee emp = employeeMapper.getEmpById(id);  return emp;}

2.自定義keyGenerator:

@Bean("myKeyGenerator")public KeyGenerator keyGenerator(){  return new KeyGenerator(){?    @Override    public Object generate(Object target, Method method, Object... params) {      return method.getName()+"["+ Arrays.asList(params).toString()+"]";    }  };}

3.CachePut的使用:更新緩存

/**   * @CachePut:既調用方法,又更新緩存數據;同步更新緩存   * 修改了數據庫的某個數據,同時更新緩存;   * 運行時機:   * 1、先調用目標方法   * 2、將目標方法的結果緩存起來   *   * 測試步驟:   * 1、查詢1號員工;查到的結果會放在緩存中;   *     key:1 value:lastName:張三   * 2、以后查詢還是之前的結果   * 3、更新1號員工;【lastName:zhangsan;gender:0】   *     將方法的返回值也放進緩存了;   *     key:傳入的employee對象 值:返回的employee對象;   * 4、查詢1號員工?   *   應該是更新后的員工;   *     key = "#employee.id":使用傳入的參數的員工id;   *     key = "#result.id":使用返回后的id   *       @Cacheable的key是不能用#result   *   為什么是沒更新前的?【1號員工沒有在緩存中更新】   *   */  @CachePut(value = "emp",key = "#result.id")  public Employee updateEmp(Employee employee){    System.out.println("updateEmp:"+employee);    employeeMapper.updateEmp(employee);    return employee;  }

4.CacheEvict 緩存清除

/** * @CacheEvict:緩存清除 * key:指定要清除的數據 * allEntries = true:指定清除這個緩存中所有的數據 * beforeInvocation = false:緩存的清除是否在方法之前執行 *   默認代表緩存清除操作是在方法執行之后執行;如果出現異常緩存就不會清除 * * beforeInvocation = true: *   代表清除緩存操作是在方法運行之前執行,無論方法是否出現異常,緩存都清除 * * */@CacheEvict(value="emp",beforeInvocation = true,key = "#id")public void deleteEmp(Integer id){  System.out.println("deleteEmp:"+id);  //employeeMapper.deleteEmpById(id);  int i = 10/0;}

5.Caching 復雜配置

// @Caching 定義復雜的緩存規則@Caching(   cacheable = {     @Cacheable(/*value="emp",*/key = "#lastName")   },   put = {     @CachePut(/*value="emp",*/key = "#result.id"),     @CachePut(/*value="emp",*/key = "#result.email")   })public Employee getEmpByLastName(String lastName){  return employeeMapper.getEmpByLastName(lastName);}

6.CacheConfig緩存清除

@CacheConfig(cacheNames="emp",cacheManager = "employeeCacheManager") //抽取緩存的公共配置@Servicepublic class EmployeeService {

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JAVA教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久精品国产久精国产思思| 久久91超碰青草是什么| 亚洲最大在线视频| 久久久免费在线观看| 亚洲欧美成人在线| 韩国19禁主播vip福利视频| 欧美激情视频一区二区| 久久久精品美女| 久久亚洲一区二区三区四区五区高| 97色在线视频观看| 欧美贵妇videos办公室| 色偷偷亚洲男人天堂| 欧美极品美女视频网站在线观看免费| 91社影院在线观看| 一区三区二区视频| 亚洲欧美日韩精品久久亚洲区| 亚洲电影在线观看| 欧美性猛交xxxx免费看| 日本一区二区三区四区视频| 国产精品pans私拍| 欧美区在线播放| 97国产suv精品一区二区62| 日本午夜精品理论片a级appf发布| 国产日韩欧美在线视频观看| 欧美激情a∨在线视频播放| 国产精品久久久久999| 亚洲国模精品私拍| 日本国产欧美一区二区三区| 欧美人与性动交a欧美精品| 久久久久北条麻妃免费看| 色婷婷久久一区二区| 亚洲久久久久久久久久久| 欧美性感美女h网站在线观看免费| 国产日韩av在线播放| 久久久久久久一区二区| 亚洲欧美国产一区二区三区| 国产91|九色| 国产日产亚洲精品| 久久久精品在线观看| 欧美成人自拍视频| 91国内免费在线视频| 日韩激情片免费| 亚洲精品日韩欧美| 精品自拍视频在线观看| 91沈先生在线观看| 欧美日韩亚洲一区二| 久久久久国产精品一区| 中文国产成人精品久久一| 成人羞羞国产免费| 欧美乱妇40p| 国产黑人绿帽在线第一区| 中文字幕国产精品久久| 久久99精品久久久久久琪琪| 性色av一区二区三区免费| 国产精品三级久久久久久电影| 亚洲精品电影网站| 91精品国产91久久久久| 国产精品va在线播放我和闺蜜| 欧美日产国产成人免费图片| 一本色道久久综合狠狠躁篇怎么玩| 最近2019中文字幕大全第二页| 91在线高清视频| 国产精品免费久久久久影院| 激情亚洲一区二区三区四区| 麻豆国产va免费精品高清在线| 欧美黄色片视频| 成人欧美一区二区三区黑人| 亚洲成av人片在线观看香蕉| 视频在线一区二区| www.xxxx精品| 中文字幕精品久久| 亚洲综合大片69999| 久久久噜久噜久久综合| 最近中文字幕日韩精品| 亚洲va码欧洲m码| 视频在线观看99| 中文字幕亚洲字幕| 国产一区二区欧美日韩| 国产精品久久久久久网站| 国产成人精品国内自产拍免费看| 色综合久久久久久中文网| 欧美国产日韩免费| 欧美日韩成人在线播放| 欧美日韩免费区域视频在线观看| 91av在线视频观看| 亚洲国产精品成人一区二区| 亚洲理论电影网| 97视频免费在线看| 日本不卡视频在线播放| 日韩一区二区欧美| 亚洲国产精品女人久久久| 中文字幕亚洲一区二区三区五十路| 久久999免费视频| 色妞欧美日韩在线| 国产精品h片在线播放| 欧美精品一区二区三区国产精品| 国产小视频国产精品| 日本精品视频网站| 久久久国产精彩视频美女艺术照福利| 欧美精品情趣视频| 国产精品午夜国产小视频| 日韩久久精品成人| 久久久成人精品视频| 亚洲国产成人久久综合一区| 国产精品专区第二| 91香蕉国产在线观看| 欧美人与性动交a欧美精品| 国产精品自产拍在线观| 正在播放欧美视频| 亚洲精品国产免费| 日韩在线播放视频| 久久99亚洲精品| 欧美一级淫片丝袜脚交| 国产成人一区二区| 国产成人欧美在线观看| 中文字幕不卡av| 中文字幕在线视频日韩| 乱亲女秽乱长久久久| 久久久999国产| 久久精彩免费视频| 欧美日韩成人网| 久久久久久久电影一区| 欧美亚洲伦理www| 日韩视频永久免费观看| 日韩成人在线免费观看| 91久久精品在线| 色狠狠av一区二区三区香蕉蜜桃| 国产精品香蕉国产| 国产精品久久电影观看| 日本三级韩国三级久久| 国产精品久久久久久久久久久新郎| 久久精品99国产精品酒店日本| 久久久噜噜噜久久中文字免| 欧美日韩高清区| 国产成人精品av| 国产一区二区三区在线观看网站| 国产精品视频在线观看| 国产亚洲欧洲黄色| 国产欧美va欧美va香蕉在| 亚洲国产精品一区二区三区| 欧美日韩综合视频网址| 国产视频精品久久久| 日韩欧美国产中文字幕| 国产午夜精品全部视频播放| 久久综合伊人77777尤物| 亚洲激情视频在线观看| 精品无人区太爽高潮在线播放| 国内精品久久影院| 日韩成人av网址| 亚洲精品av在线播放| 色婷婷综合成人av| 亚洲女人天堂成人av在线| 中文字幕欧美视频在线| 亚洲va欧美va国产综合剧情| 亚洲色图美腿丝袜| 国产精品v日韩精品| 色播久久人人爽人人爽人人片视av| 91大神在线播放精品| 日韩三级影视基地| 欧美激情精品久久久久久黑人| 中文字幕久久亚洲| 欧美午夜丰满在线18影院| 国产mv免费观看入口亚洲| 91精品视频大全|