真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

cache如何在Springboot中使用

cache如何在Spring boot中使用?相信很多沒(méi)有經(jīng)驗(yàn)的人對(duì)此束手無(wú)策,為此本文總結(jié)了問(wèn)題出現(xiàn)的原因和解決方法,通過(guò)這篇文章希望你能解決這個(gè)問(wèn)題。

為企業(yè)提供成都做網(wǎng)站、成都網(wǎng)站制作、成都外貿(mào)網(wǎng)站建設(shè)、網(wǎng)站優(yōu)化、全網(wǎng)營(yíng)銷推廣、競(jìng)價(jià)托管、品牌運(yùn)營(yíng)等營(yíng)銷獲客服務(wù)。創(chuàng)新互聯(lián)擁有網(wǎng)絡(luò)營(yíng)銷運(yùn)營(yíng)團(tuán)隊(duì),以豐富的互聯(lián)網(wǎng)營(yíng)銷經(jīng)驗(yàn)助力企業(yè)精準(zhǔn)獲客,真正落地解決中小企業(yè)營(yíng)銷獲客難題,做到“讓獲客更簡(jiǎn)單”。自創(chuàng)立至今,成功用技術(shù)實(shí)力解決了企業(yè)“網(wǎng)站建設(shè)、網(wǎng)絡(luò)品牌塑造、網(wǎng)絡(luò)營(yíng)銷”三大難題,同時(shí)降低了營(yíng)銷成本,提高了有效客戶轉(zhuǎn)化率,獲得了眾多企業(yè)客戶的高度認(rèn)可!

Spring 的緩存技術(shù)還具備相當(dāng)?shù)撵`活性,不僅能夠使用 SpEL(Spring Expression Language)來(lái)定義緩存的 key 和各種 condition,還提供開箱即用的緩存臨時(shí)存儲(chǔ)方案,也支持和主流的專業(yè)緩存例如 EHCache 集成。

其特點(diǎn)總結(jié)如下:

1. 通過(guò)少量的配置 annotation 注釋即可使得既有代碼支持緩存
2. 支持開箱即用 Out-Of-The-Box,即不用安裝和部署額外第三方組件即可使用緩存
3. 支持 Spring Express Language,能使用對(duì)象的任何屬性或者方法來(lái)定義緩存的 key 和 condition
4. 支持 AspectJ,并通過(guò)其實(shí)現(xiàn)任何方法的緩存支持
5. 支持自定義 key 和自定義緩存管理者,具有相當(dāng)?shù)撵`活性和擴(kuò)展性

一、Spring boot cache原理

第一步、自動(dòng)配置類;

自動(dòng)啟動(dòng)類:CacheAutoConfiguration

屬性配置:CacheProperties

主啟動(dòng)類添加:@EnableCaching注解

cache POM添加:


  org.springframework.boot
  spring-boot-starter-cache

第二步、從緩存的配置類 中獲取 多個(gè)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;
    }

}

獲取結(jié)果:SimpleCacheConfiguration 默認(rèn)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【默認(rèn)】
  org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration

第三步:SimpleCacheConfiguration.cacheManager()

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

@Bean
public ConcurrentMapCacheManager cacheManager() {
  ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();
  List cacheNames = this.cacheProperties.getCacheNames();
  if (!cacheNames.isEmpty()) {
   cacheManager.setCacheNames(cacheNames);
  }
  return this.customizerInvoker.customize(cacheManager);
}

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

ConcurrentMapCacheManager 類里,數(shù)據(jù)都存儲(chǔ)到為ConcurrentMap 中

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

二、Cacheable運(yùn)行流程:

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

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

3、沒(méi)有查到緩存就調(diào)用目標(biāo)方法; 4、將目標(biāo)方法返回的結(jié)果,放進(jìn)緩存中ConcurrentMapCache.put();

@Cacheable標(biāo)注的方法執(zhí)行之前先來(lái)檢查緩存中有沒(méi)有這個(gè)數(shù)據(jù),默認(rèn)按照參數(shù)的值作為key去查詢緩存, 如果沒(méi)有就運(yùn)行方法并將結(jié)果放入緩存;以后再來(lái)調(diào)用就可以直接使用緩存中的數(shù)據(jù);

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

詳細(xì)執(zhí)行流程:ConcurrentMapCache.lookup()上斷點(diǎn)查看,執(zhí)行過(guò)程

//第一步CacheAspectSupport 中execute()
private Object execute(final CacheOperationInvoker invoker, Method method, CacheOperationContexts contexts) 
//第二步 CacheAspectSupport
private Cache.ValueWrapper findCachedItem(Collection 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();
@Override
public ValueWrapper get(Object key) {
    Object value = lookup(key);
    return toValueWrapper(value);
}
// 第六步:ConcurrentMapCache.lookup(); 從ConcurrentMap 中根據(jù)key獲取值
@Override
protected Object lookup(Object key) {
    return this.store.get(key);
}

三、Cacheable 注解的幾個(gè)屬性:

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

2、key:緩存數(shù)據(jù)使用的key;可以用它來(lái)指定。默認(rèn)是使用方法參數(shù)的值 1-方法的返回值

編寫SpEL; #i d;參數(shù)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":第一個(gè)參數(shù)的值》1的時(shí)候才進(jìn)行緩存

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

unless = "#result == null"

unless = "#a0==2":如果第一個(gè)參數(shù)的值是2,結(jié)果不緩存;

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+"號(hào)員工");
  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:既調(diào)用方法,又更新緩存數(shù)據(jù);同步更新緩存
   * 修改了數(shù)據(jù)庫(kù)的某個(gè)數(shù)據(jù),同時(shí)更新緩存;
   * 運(yùn)行時(shí)機(jī):
   * 1、先調(diào)用目標(biāo)方法
   * 2、將目標(biāo)方法的結(jié)果緩存起來(lái)
   *
   * 測(cè)試步驟:
   * 1、查詢1號(hào)員工;查到的結(jié)果會(huì)放在緩存中;
   *     key:1 value:lastName:張三
   * 2、以后查詢還是之前的結(jié)果
   * 3、更新1號(hào)員工;【lastName:zhangsan;gender:0】
   *     將方法的返回值也放進(jìn)緩存了;
   *     key:傳入的employee對(duì)象 值:返回的employee對(duì)象;
   * 4、查詢1號(hào)員工?
   *   應(yīng)該是更新后的員工;
   *     key = "#employee.id":使用傳入的參數(shù)的員工id;
   *     key = "#result.id":使用返回后的id
   *       @Cacheable的key是不能用#result
   *   為什么是沒(méi)更新前的?【1號(hào)員工沒(méi)有在緩存中更新】
   *
   */
  @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:指定要清除的數(shù)據(jù)
 * allEntries = true:指定清除這個(gè)緩存中所有的數(shù)據(jù)
 * beforeInvocation = false:緩存的清除是否在方法之前執(zhí)行
 *   默認(rèn)代表緩存清除操作是在方法執(zhí)行之后執(zhí)行;如果出現(xiàn)異常緩存就不會(huì)清除
 *
 * beforeInvocation = true:
 *   代表清除緩存操作是在方法運(yùn)行之前執(zhí)行,無(wú)論方法是否出現(xiàn)異常,緩存都清除
 *
 *
 */
@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 復(fù)雜配置

// @Caching 定義復(fù)雜的緩存規(guī)則
@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") //抽取緩存的公共配置
@Service
public class EmployeeService {

看完上述內(nèi)容,你們掌握cache如何在Spring boot中使用的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!


名稱欄目:cache如何在Springboot中使用
鏈接地址:http://weahome.cn/article/psgshs.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部