SpringBoot 缓存 – jetcache

简介

JetCache是一个基于Java的缓存系统封装,提供统一的API和强大的注解来简化缓存的使用。原生支持TTL、两级缓存、分布式自动刷新,还提供了Cache接口用于手工缓存操作。主要是用来替代Springboot 自带的Cache服务。

添加依赖

使用jetcache,需要引入相关依赖,jetcache的远程缓存使用的是redis,同时使用的redis是jedis,因此需要在集成的redis组件里排除lettuce连接池

<!-- 添加jetcahce依赖 -->
<dependency>
   <groupId>com.alicp.jetcache</groupId>
   <artifactId>jetcache-starter-redis</artifactId>
   <version>2.7.0</version>
</dependency>

<!-- 引入redis,同时排除默认的lettuce连接池 -->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
   <exclusions>
      <exclusion>
         <groupId>io.lettuce</groupId>
         <artifactId>lettuce-core</artifactId>
      </exclusion>
   </exclusions>
</dependency>

<!-- 引入 redis jedis 连接池 -->
<dependency>
   <groupId>redis.clients</groupId>
   <artifactId>jedis</artifactId>
</dependency>

<!-- 引入fastjson -->
<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>fastjson</artifactId>
   <version>1.2.75</version>
</dependency>

使用

配置jetcache

在application.yml配置文件添加以下配置项:

jetcache:
  statIntervalMinutes: 15
  areaInCacheName: false
  local:   # 本地缓存配置,即无法实现分布式,该缓存只对当台机器有效,在其它机器无法共享缓存信息
    default:
      type: linkedhashmap
      keyConvertor: fastjson
      limit: 100
  remote:  # 远程缓存配置,所有机器共享缓存
    default:
      type: redis
      keyConvertor: fastjson
      valueEncoder: java
      valueDecoder: java
      poolConfig:
        minIdle: 5
        maxIdle: 20
        maxTotal: 50
      host: 127.0.0.1
      port: 6379

启用jetcache

在启动类中添加@EnableMethodCache注解,其中basePackages指定启用注解的包,一般填写启动类的包名,如下:

@SpringBootApplication
@EnableMethodCache(basePackages = "com.example.cache")
public class CacheApplication {

    public static void main(String[] args) {
        SpringApplication.run(CacheApplication.class, args);
    }

}

创建缓存

使用@Cached方法为一个方法添加上缓存。JetCache通过Spring AOP生成代理,来支持缓存功能。注解可以加在接口方法上也可以加在类方法上,但需要保证是个归spring容器管理的SpringBean。

案例

public interface JetCacheService {
  @Cached(name = "student_cache_", key = "#id", expire = 3600)
  Student getStudent(Long id);
}

@Service
public class JetCacheServiceImpl implements JetCacheService {
  	@Override
    public Student getStudent(Long id) {
        Student student = new Student();
        student.setId(id);
        student.setAge(15);
        student.setName("李四");
        student.setGrade("高一");
        student.setCreatedTime(LocalDateTime.now());
        System.out.println("正在进行创建缓存");
        return student;
    }
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student implements Serializable {
    private Long id;
    private String name;
    private int age;
    private String grade;
    private LocalDateTime createdTime;
}

测试

@SpringBootTest
class JetCacheServiceImplTest {
  
    @Autowired
    private JetCacheService jetCacheService;

    @Test
    void getStudent() {
        Student student =  jetCacheService.getStudent(1L);
        System.out.println(student);
    }
}

第一次运行测试结果如下:

正在进行创建缓存
Student(id=1, name=李四, age=15, grade=高一, createdTime=2022-10-22T13:09:05.960)

第二次运行测试结果如下:

Student(id=1, name=李四, age=15, grade=高一, createdTime=2022-10-22T13:09:05.960)

从上面两次的测试运行结果可以看出,正在进行创建缓存这行文件在第二次测试运行时并没有进行输出,则可以说明,第二次运行获取到的数是直接从缓存中获取的,并没有执行getStudent方法里面的相关代码。

@Cached 注解解析

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Cached {
  
  	// 缓存区域,默认为default
    String area() default "default";

  	// 缓存实例的名称,可用作显示统计信息和作为key的前缀
    String name() default "$$undefined$$";
    
    // 缓存是否生效,默认为true
    boolean enabled() default true;

    // 缓存时间的单位,默认为秒
    TimeUnit timeUnit() default TimeUnit.SECONDS;

    // 过期时间,如果未配置localExpire则本地缓存和remote缓存都使用此
    int expire() default Integer.MIN_VALUE;

    // 本地缓存的过期时间
    int localExpire() default Integer.MIN_VALUE;

  	// 缓存类型,可选EMOTE(远端), LOCAL(本地), BOTH(本地与远端同时缓存)
    CacheType cacheType() default CacheType.REMOTE;

    // 本地缓存最大数量
    int localLimit() default Integer.MIN_VALUE;

    // 序列化方式,默认使用全局
    String serialPolicy() default "$$undefined$$";

    // 指定**转换器。用于转换复杂的**对象。JetCache内置版本keyConvertor是KeyConvertor.FASTJSON或KeyConvertor.NONE。NONE表示不转换,FASTJSON将使用fastjson将key对象转换为字符串。如果缺少属性值,请使用全局配置。
    String keyConvertor() default "$$undefined$$";

    // 缓存key,使用spel表达式
    String key() default "$$undefined$$";

    // 是否缓存null
    boolean cacheNullValue() default false;

    // 使用SpEL指定条件,如果表达式返回true的时候才去缓存中查询
    String condition() default "$$undefined$$";

    // 表达式脚本用于调节方法缓存更新,当评估结果为假时,缓存操作被否决。在实际方法调用之后进行评估,因此我们可以在脚本中引用#result。
    String postCondition() default "$$undefined$$";
}

缓存更新

在方法上面添加@CacheUpdate注解可以进行缓存更新,注解可以加在接口方法上也可以加在类方法上,案例如下:

案例

public interface JetCacheService {
   @CacheUpdate(name = "student_cache_", key = "#student.id", value = "#student")
    Student updateStudent(Student student);
}

@Service
public class JetCacheServiceImpl implements JetCacheService {
  	@Override
    public Student updateStudent(Student student) {
        System.out.println("update student:" + student);
        return student;
    }
}


@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student implements Serializable {
    private Long id;
    private String name;
    private int age;
    private String grade;
    private LocalDateTime createdTime;
}

测试

@SpringBootTest
class JetCacheServiceImplTest {

    @Autowired
    private JetCacheService jetCacheService;
   
  	@Test
    void updateStudent() {
        System.out.println(jetCacheService.getStudent(1L));
        Student student = new Student();
        student.setId(1L);
        student.setAge(18);
        student.setName("李四");
        student.setGrade("高三");
        student.setCreatedTime(LocalDateTime.now());
        jetCacheService.updateStudent(student);
        System.out.println(jetCacheService.getStudent(1L));
    }
}

运行测试案例,输出结果如下:

Student(id=2, name=李四, age=15, grade=高一, createdTime=2022-10-22T13:33:07.812)
update student:Student(id=2, name=李四, age=18, grade=高三, createdTime=2022-10-22T13:33:07.835)
Student(id=2, name=李四, age=18, grade=高三, createdTime=2022-10-22T13:33:07.835)

从输出结果可以看出,第一行输出是没有进行缓存更新前的数据输出,第二行是需要缓存更新的更新,第三行输出是缓存更新后,从缓存中获取出来的数据,因此可以看出缓存更新成功。

@CacheUpdate 注解解析

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface CacheUpdate {
  
    // 缓存区域,默认default, 一般情况下不需要设置
    String area() default "default";

    // 缓存实例的名称,可用作显示统计信息和作为key的前缀
    String name();

    // 缓存key,使用spel表达式
    String key() default "$$undefined$$";

    // 使用spel表达式指定缓存数据
    String value();
  
    // 缓存条件,true更新缓存,false不更新缓存,使用spel指定
    String condition() default "$$undefined$$";

    boolean multi() default false;
}

缓存删除

在方法上面添加@CacheInvalidate注解进行缓存删除,注解可以加在接口方法上也可以加在类方法上,案例如下:

案例

public interface JetCacheService {
  
  @CacheInvalidate(name = "student_cache_", key = "#id")
  void deleteStudent(Long id);
  
}

@Service
public class JetCacheServiceImpl implements JetCacheService {
  
  @Override
  public void deleteStudent(Long id) {
      System.out.println("deleteStudent:" + id);
  }
  
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student implements Serializable {
    private Long id;
    private String name;
    private int age;
    private String grade;
    private LocalDateTime createdTime;
}

@CacheInvalidate 注解解析

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(CacheInvalidateContainer.class)
@Target({ElementType.METHOD})
public @interface CacheInvalidate {
  
    // 缓存区域,默认为default
    String area() default "default";

    // 缓存实例的名称,可用作显示统计信息和作为key的前缀
    String name();

    // 缓存key,使用spel表达式
    String key() default "$$undefined$$";

    // 缓存条件,true删除缓存,false不删除缓存,使用spel指定
    String condition() default "$$undefined$$";

    boolean multi() default false;
}

缓存刷新

在方法上面添加@CacheRefresh注解可以进行缓存自动刷新,即只要请求过一次缓存,后面会自动进行后台刷新,例如:

public interface JetCacheService {

    @Cached(name = "student_cache_", key = "#id", expire = 3600)
    @CacheRefresh(refresh = 10)
    Student getStudent(Long id);
  
}

@Service
public class JetCacheServiceImpl implements JetCacheService {

    @Override
    public Student getStudent(Long id) {
        Student student = new Student();
        student.setId(id);
        student.setAge(15);
        student.setName("李四");
        student.setGrade("高一");
        student.setCreatedTime(LocalDateTime.now());
        System.out.println(LocalDateTime.now());
        System.out.println("正在进行创建缓存");
        System.out.println(student);
        return student;
    }
  
}

测试

@RestController
@RequestMapping("/jetcache")
public class JetCacheController {

    @Autowired
    private JetCacheService jetCacheService;

    @GetMapping
    public Student getStudent(){
        Student student = jetCacheService.getStudent(1L);
        return student;
    }
}

启动应用,访问URL: http://localhost:8080/jetcache,然后查看控制台输出,输出如下:

2022-10-22T21:35:55.145
正在进行创建缓存
Student(id=1, name=李四, age=15, grade=高一, createdTime=2022-10-22T21:35:55.145)
2022-10-22T21:36:05.154
正在进行创建缓存
Student(id=1, name=李四, age=15, grade=高一, createdTime=2022-10-22T21:36:05.154)
2022-10-22T21:36:15.163
正在进行创建缓存
Student(id=1, name=李四, age=15, grade=高一, createdTime=2022-10-22T21:36:15.163)

从上面可以看出,每隔10秒就会自动进行缓存刷新。

@CacheRefresh 注解解析

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD})
public @interface CacheRefresh {
  
  	// 隔多久进行刷新
    int refresh();
    
    // 指定该key多长时间没有访问就停止刷新,如果不指定会一直刷新
    int stopRefreshAfterLastAccess() default Integer.MIN_VALUE;
	
    // 类型为BOTH/REMOTE的缓存刷新时,同时只会有一台服务器在刷新,这台服务器会在远程缓存放置一个分布式锁,此配置指定该锁的超时时间
    int refreshLockTimeout() default Integer.MIN_VALUE;
   
    // 间隔时间单位,默认是秒
    TimeUnit timeUnit() default TimeUnit.SECONDS;
}

更多信息,请查看官方文档:GitHub - alibaba/jetcache: JetCache is a Java cache framework.

原创文章,作者:jiafegn,如若转载,请注明出处:https://www.techlearn.cn/archives/505

Previous 2023年4月23日 下午10:47
Next 2023年4月24日

相关推荐

  • SpringBoot 过滤器

    简介 SpringBoot过滤器在web开发中可以过滤指定的URL,比如拦截掉不需要的接口请求,同时也可以对request和response的内容进行修改。 使用场景 Spring…

    springboot 2023年4月30日
    241
  • SpringBoot 打包

    SpringBoot 项目部署到服务器常见的方式就是,打包成 jar 包,通过 nohup java -jar 命令去运行项目,这也是官方推荐的一种方式。 导入依赖 打包 设置打包…

    springboot 2023年4月5日
    148
  • SpringBoot 分布式定时任务-Quartz

    简介 Quartz是完全由Java开发的一个开源的作业调度框架。在业务系统中,主要用于做分布式定时任务。Spring本身提供的@Schedule只能实现一些相对简单的单机定时任务,…

    springboot 2023年12月17日
    371
  • SpringBoot自定义注解与使用

    简介 注解是一种能添加到Java代码中的元数据,方法,类,参数与包都可以使用注解进行修饰,可以将注解看为一种特殊的标记,在Java编译或运行过程中将有这种特殊标记的部分进行特殊处理…

    springboot 2024年1月25日
    254
  • SpringBoot Spring Event 业务解耦神器

    介绍 Spring Event是Spring框架中的一个事件机制,主要用于实现应用程序内部的事件传递与处理,它允许不同组件之间通过发布-订阅机制进行解耦通信,比如用户注册,订单创建…

    springboot 2024年1月11日
    301
  • SpringBoot拦截器

    简介 拦截器可以根据 URL 对请求进行拦截,主要应用于登陆校验、权限验证、乱码解决、性能监控和异常处理等功能。 使用步骤 在SpringBoot中使用拦截器功能通常需要以下3步:…

    springboot 2023年4月29日
    123
  • SpringBoot 整合SpringSecurity认证

    简介 Spring Security 是Spring家族中的一个安全管理框架。相比与另外一个安全框架shiro,它提供了更丰富的功能,社区资源也比Shiro丰富。 —般Web应用的…

    2023年12月31日
    424
  • SpringBoot 全局异常统一处理

    前言 在实际的项目开发过程中,会有大量的异常发生,而我们并不能将异常信息反馈到用户,所以在返回结果的时候需要对异常进行处理,可是如果在每个Controller返回结果都需要进行异常…

    springboot 2023年4月29日
    125
  • springboot 注解 @Qualifier

    作用 可以在依赖注入查找候选者的过程中对候选者进行过滤,比如:在需要自动注入java bean时,如果注入的是一个接口,而这个接口又有多个实现类,则会报错,解决方法是在注入接口上增…

    springboot 2022年9月14日
    199
  • Springboot 注解 @DependsOn

    作用 @DependsOn用来指定当前bean依赖的bean,spring在创建bean的时候,如果bean之间没有依赖关系,那么spring容器很难保证bean实例创建的顺 序,…

    springboot 2022年9月1日
    368