JetCache - 通用缓存框架

JetCache

JetCache是由阿里巴巴开源的通用缓存访问框架,如果你对Spring Cache很熟悉的话,请一定花一点时间了解一下JetCache,它更好用。

JetCache提供的核心能力包括:

  • 提供统一的,类似jsr-107风格的API访问Cache,并可通过注解创建并配置Cache实例
  • 通过注解实现声明式的方法缓存,支持TTL和两级缓存
  • 分布式缓存自动刷新,分布式锁 (2.2+)
  • 支持异步Cache API
  • Spring Boot支持
  • Key的生成策略和Value的序列化策略是可以定制的
  • 针对所有Cache实例和方法缓存的自动统计

1.1 常见的使用场景

public interface UserService {
    @Cached(name="UserService.getUserById", expire = 3600)
    User getUserById(long userId);
}

 

expire: 过期时间
CacheType : 缓存类型

@Cached注解,支持TTL(超时时间),CacheType有三种类型:LOCAL,REMOTE,BOTH
本地内存/远程/两级缓存,可根据情况合理选用,使用得当,可以减低Cache Server的压力以及服务器的响应时间。

1.2 方法缓存

public class ShopInfoProviderImpl implements ShopInfoProvider{

    @Override
    @Cached(name="shopServer.shop",key="#shopId",expire = 3600, cacheType = CacheType.REMOTE)
    public Shop getShopById(Long shopId) {
        return null;
    }

    @Override
    @CacheUpdate(name="shopServer.shop",key="#shopId",value="#user")
    public void modifyShop(Long shopId) {

    }

    @Override
    @CacheInvalidate(name="shopServer.shop",key="#shopId")
    public void removeShop(Long shopId) {

    }

 }

 上面代码中可以看出,我们可以使用SpEL(Spring Expression Language)来设置key和Value,当入参是对象时,可以使用对象中的一个字段,如 #user.userId 来设置。name属性不是必须的,但是起个名字是个好习惯,展示统计数据的使用,会使用这个名字。如果同一个area两个@CreateCache的name配置一样,它们生成的Cache将指向同一个实例。这里面需要注意的是,java代码的编辑级别必须是1.8。

 如果没有指定Key,那么系统会自动根据参数生成。

1.3 刷新缓存

    @Override
    @Cached(expire = 3600, cacheType = CacheType.REMOTE)
    @CacheRefresh(refresh = 1800, stopRefreshAfterLastAccess = 3600, timeUnit =TimeUnit.SECONDS)
    public void totalShop(Long shopId){

    }

 

CacheType为REMOTE或者BOTH的时候,刷新行为是全局唯一的,也就是说,即使应用服务器是一个集群,也不会出现多个服务器同时去刷新同一个Key的情况。

一个Key的刷新任务,自该Key首次被访问后初始化,如果该Key部不被访问,在stopRefreshAfterLastAccess指定的时间后,相关的刷新任务就会被自动移除,这样避免了浪费资源去进行没有意义的刷新。

CachePenetrationProtect表示在多线程环境中同步加载数据。

1.4 实例缓存

@CreateCache(expire = 100)
private Cache<Long, ShopDO> shopCache;

用起来就像map

ShopDO shop = shopCache.get(123L);
shopCache.put(123L, shop);
shopCache.remove(123L);

创建一个两级(内存+远程)的缓存,内存中的元素个数限制在50个。

@CreateCache(name = "ShopServer.shopCache", expire = 100, cacheType = CacheType.BOTH, localLimit = 50)
private Cache<Long, ShopDO> shopCache;

1.5 基本配置(SpringBoot)

1)pom.xml 

<dependency>
   <groupId>com.alicp.jetcache</groupId>
   <artifactId>jetcache-starter-redis</artifactId>
   <version>2.4.4</version>
</dependency>

2)application.yml更新:

jetcache:
  statIntervalMinutes: 15
  areaInCacheName: false
  local:
    default:
      type: linkedhashmap
      keyConvertor: fastjson
  remote:
    default:
      type: redis
      keyConvertor: fastjson
      valueEncoder: java
      valueDecoder: java
      poolConfig:
        minIdle: 5
        maxIdle: 20
        maxTotal: 50
      host: 192.168.0.223
      port: 6380

3)创建一个App类放在业务包得根下,EnableMethodCache,EnableCreateCacheAnnotation这两个注解分别激活Cached和CreateCache注解,其他和标准的SpringBoot程序是一样的,这个类可以直接main方法运行

package com.owner.im;

import com.alicp.jetcache.anno.config.EnableCreateCacheAnnotation;
import com.alicp.jetcache.anno.config.EnableMethodCache;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableMethodCache(basePackages = "com.owner.im")
@EnableCreateCacheAnnotation
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

 

4)验证结果

package com.owner.im.web;

import com.alicp.jetcache.Cache;
import com.alicp.jetcache.anno.CacheType;
import com.alicp.jetcache.anno.CreateCache;
import com.owner.im.model.ShopDO;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
public class LoginController {

    @CreateCache(expire = 300, cacheType = CacheType.LOCAL,timeUnit = TimeUnit.SECONDS)
    private Cache<Long, ShopDO> shopCache;

    @GetMapping("/login")
    public String login(@RequestParam(name = "id") Long id, @RequestParam(name = "name") String name) {
        System.out.println("请求参数:ID == " + id + "NAME == " + name);
        ShopDO shopDO = new ShopDO();
        shopDO.setId(id);
        shopDO.setName(name);
        shopCache.put(id, shopDO);
        System.out.println("对象已放入,缓存有效期300s");
        return shopCache.get(id).getId() + shopCache.get(id).getName();
    }

    @GetMapping("/getLoginInfo")
    public void getLogin(@RequestParam(name = "id") Long id) {
        ShopDO shopDO = shopCache.get(id);
        if (null == shopDO) {
            System.out.println("刷新后缓存失效");
        }else{
            System.out.println("刷新后缓存为:" + shopCache.get(id).getId() + shopCache.get(id).getName());
        }

    }

}

上图红框中内容必填。必须指定CacheType类型,否则会报错。300s后,重新访问方法2,缓存失效。

项目中真实案列:

方法级别缓存:

    @Override
    @Cached(area = "activity-server", name = "getSpecialStartTimeRecent3Days", key = "'endTime:'+#endTime", expire = 1, timeUnit = TimeUnit.DAYS)
    @CacheRefresh(refresh = 6,  timeUnit = TimeUnit.HOURS)
    public List<Timestamp> getSpecialStartTimeRecent3Days(Timestamp endTime) {
        return activitySpecialDao.selectSpecialStartTimeRecent3Days(endTime);
    }

   以下代码,定义了缓存得area,name,key,过期时间。然后设定了定时刷新为6h.

方法缓存刷新:

@Override
    @Cached(area = "activity-server", name = "getSpecialStartTimeRecent3Days", key = "'endTime:'+#endTime", expire = 1, timeUnit = TimeUnit.DAYS)
    @CacheRefresh(refresh = 6,  timeUnit = TimeUnit.HOURS)
    public List<Timestamp> getSpecialStartTimeRecent3Days(Timestamp endTime) {
        return activitySpecialDao.selectSpecialStartTimeRecent3Days(endTime);
    }
 

  @Override
    @CacheInvalidate(area = "activity-server", name = "getSpecialStartTimeRecent3Days", key = "'endTime:'+#endTime")
    public boolean freshSpecialStartTimeRecent3Days(Timestamp endTime){
        logger.error("删除缓存getSpecialStartTimeRecent3Days");
        return true;
    }

方法级别缓存刷新,建议使方法缓存失效,不要用那个刷新;另外使用注解得形式JetCache是基于切面形式,加缓存与刷新缓存的注解必须在同一个类中,但是调用刷缓存的地方必须多封装一层,另外刷新缓存的入参必须与加缓存入参保持一致。

// 以下为调用缓存刷新的代码
SpecialFacade.java  
public void updateSpecialTimes(){
        DateTime yesterday = new DateTime().minusDays(1);
        DateTime tomorrow = new DateTime().plus(1);
        Timestamp startTime = Timestamp.valueOf(yesterday.toString("yyyy-MM-dd 00:00:00"));
        Timestamp endTime = Timestamp.valueOf(tomorrow.toString("yyyy-MM-dd 23:59:59"));
        activitySpecialService.freshSpecialStartTimeRecent3DayNoRealTime(startTime,endTime);
    }

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值