轻松使用spring cache(一)

一、前言#

因业务需求,需要使用spring-data-cache进行方法缓存.在闲暇之余看了一下spring的官方文档,感觉还是挺简单,在此记录一下.

二、Spring Cache为什么开箱即用?#

spring设计的非常的简单,使用起来只需要五个注解一个简单的配置即可完成.是不是挺简单的?涉及的注解有@CacheConfig@Cacheable@CachePut@CacheEvict@EnableCaching,设计的配置类有CacheManagerCachingConfigurerCacheResolverKeyGeneratorCacheErrorHandler.是不是感觉挺少的?感觉这种学习成本很低呀!

三、相关注解#

  1. EnableCaching

    • 描述: 开启缓存自动配置

    • 使用方法:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      @SpringBootApplication
      //开启缓存自动配置
      @EnableCaching
      public class CacheDemoApplication {


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

      }

      //配置cacheManager
      @Bean
      public CacheManager cacheManager(RedisTemplate<String,Object> redisTemplate) {

      RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate);
      //设置缓存名称
      redisCacheManager.setCacheNames(new ArrayList<String>(){{
      add("UserCache");
      }});
      //设置缓存默认前缀
      redisCacheManager.setCachePrefix(new DefaultRedisCachePrefix("-"));

      //redisCacheManager.setUsePrefix(true);
      redisCacheManager.afterPropertiesSet();
      return redisCacheManager;
      }

      //配置cache使用过程中的错误处理器
      @Bean
      public CacheErrorHandler cacheErrorHandler(){

      return new CacheErrorHandler() {
      @Override
      public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {

      }

      @Override
      public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) {

      }

      @Override
      public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {

      }

      @Override
      public void handleCacheClearError(RuntimeException exception, Cache cache) {

      }
      };
      }

      //配置redis
      @Bean
      public RedisTemplate<String,Object> redisTemplate(JedisConnectionFactory connectionFactory){

      RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
      redisTemplate.setConnectionFactory(connectionFactory);
      redisTemplate.setKeySerializer(new StringRedisSerializer());
      redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
      return redisTemplate;
      }


      }
  2. Cacheable

    • 描述: 方法级别的注解,使用方法的参数作为key,如果缓存命中就直接返回结果,不再执行方法具体逻辑,如果未命中则执行方法的具体逻辑,并将方法的返回值缓存.
    • 参数:
      • value : 指定缓存名称,是cacheNames的别名
      • cacheNames: 指定缓存名称,是value的别名
      • key: 指定缓存的key,支持spring EL 表达式
      • keyGenerator: 指定key生成器,需要自己进行配置,不过一般情况使用默认的就够用了
      • cacheManager: 指定缓存管理器,需要自己配置
      • cacheResolver: 指定缓存解析器,需要自己配置,用于定制缓存的使用逻辑
      • condition: 用于条件判断,返回true才缓存,否则不缓存,支持spring EL表达式.执行在方法逻辑前
      • unless: 用于条件判断,与condition作用相反,支持spring EL 表达式,执行在方法逻辑后,能拿到结果值
      • sync: 是否同步,默认为false,如为true,将阻塞后面相同操作,只到有返回值为止
  3. CachePut

  • 描述: 用于更新缓存,与Cacheable不一样,始终会执行方法逻辑,并把返回值缓存.由于参数都差不多,就不再赘述了.
  1. CacheEvict
  • 描述: 用于清理缓存.下面介绍一下与前面不一样的参数.
  • 参数:
    • allEntries: 是否清理掉所有缓存,默认为false
    • beforeInvocation: 用于控制执行实际,默认是false,在方法之后执行,true则是在方法之前执行.
  1. Caching
  • 描述: 用于串联前面三种操作
  • 参数:
    • Cacheable: 缓存
    • CachePut: 更新缓存
    • CacheEvict: 清除缓存
  1. CacheConfig
  • 描述: 类级别的注解,用于同一管理一个类中的缓存配置,具体的看参数,由于参数前面都介绍了,不再赘述了.

四、相关类#

  1. CacheManager
  • 描述:用于管理缓存,具体使用方法后面会介绍
  1. CacheErrorHandler
  • 描述: 缓存错误处理器,用于缓存错误处理
  1. CacheResolver
    • 描述: 用于自定义如何使用缓存的策略
  2. KeyGenerator
    • 描述: 用于自定义生成key的策略,不过使用的默认的就够用了,除非有特殊的场景
  3. CachingConfigurer
    • 描述: 一个接口,用于配置上面4个.不一定用这个进行配置,可以单独配置.

五、简单使用#

  1. model

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    package com.zzwtec.cache.demo.model;

    import java.util.Objects;

    public class User {

    private String id;
    private String name;
    private String email;

    public String getId() {
    return id;
    }

    public void setId(String id) {
    this.id = id;
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    public String getEmail() {
    return email;
    }

    public void setEmail(String email) {
    this.email = email;
    }

    @Override
    public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    User user = (User) o;
    return Objects.equals(id, user.id) &&
    Objects.equals(name, user.name) &&
    Objects.equals(email, user.email);
    }

    @Override
    public int hashCode() {

    return Objects.hash(id, name, email);
    }

    @Override
    public String toString() {
    return "User{" +
    "id='" + id + '\'' +
    ", name='" + name + '\'' +
    ", email='" + email + '\'' +
    '}';
    }
    }
  2. dao

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    package com.zzwtec.cache.demo.dao;

    import com.zzwtec.cache.demo.model.User;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Repository;

    @Repository
    public class UserDao {
    private static final Logger LOGGER = LoggerFactory.getLogger(UserDao.class);

    public User findByUserId(String userId){
    LOGGER.info("query database ......");
    User user = new User();
    user.setId(userId);
    user.setEmail("[email protected]");
    user.setName("admin");
    return user;
    }


    public User saveUser(User user){
    LOGGER.info("save user ......");
    return user;
    }


    public User updateUser(User user){

    LOGGER.info("update user .....");
    return user;
    }


    public boolean deleteUserById(String userId){
    LOGGER.info("delete user ....");
    return true;
    }
    }
  3. service

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    package com.zzwtec.cache.demo.service;

    import com.zzwtec.cache.demo.dao.UserDao;
    import com.zzwtec.cache.demo.model.User;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cache.annotation.*;
    import org.springframework.stereotype.Service;

    @Service
    @CacheConfig(cacheNames = "UserCache")
    public class UserService {

    private final UserDao userDao;


    @Autowired
    public UserService(UserDao userDao) {
    this.userDao = userDao;
    }

    @Cacheable(key = "#userId")
    public User findUserById(String userId){

    return userDao.findByUserId(userId);
    }

    @CachePut(key = "#user.id")
    @Caching()
    public User saveUser(User user){

    return userDao.saveUser(user);
    }

    @CachePut(key = "#user.id")
    public User updateUserById(User user){

    return userDao.updateUser(user);
    }

    @CacheEvict
    public boolean deleteUserById(String userId){

    return userDao.deleteUserById(userId);
    }

    }
  4. 启动类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    package com.zzwtec.cache.demo;

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cache.Cache;
    import org.springframework.cache.CacheManager;
    import org.springframework.cache.annotation.EnableCaching;
    import org.springframework.cache.interceptor.CacheErrorHandler;
    import org.springframework.context.annotation.Bean;
    import org.springframework.data.redis.cache.DefaultRedisCachePrefix;
    import org.springframework.data.redis.cache.RedisCacheManager;
    import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
    import org.springframework.data.redis.serializer.StringRedisSerializer;

    import java.util.ArrayList;

    @SpringBootApplication
    @EnableCaching
    public class CacheDemoApplication {


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

    }


    @Bean
    public CacheManager cacheManager(RedisTemplate<String,Object> redisTemplate) {

    RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate);
    //设置缓存名称
    redisCacheManager.setCacheNames(new ArrayList<String>(){{
    add("UserCache");
    }});
    //设置缓存默认前缀
    redisCacheManager.setCachePrefix(new DefaultRedisCachePrefix("-"));
    //是否使用前缀
    redisCacheManager.setUsePrefix(true);
    redisCacheManager.afterPropertiesSet();
    return redisCacheManager;
    }


    @Bean
    public CacheErrorHandler cacheErrorHandler(){
    //默认不做处理
    return new CacheErrorHandler() {
    @Override
    public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {

    }

    @Override
    public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) {

    }

    @Override
    public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {

    }

    @Override
    public void handleCacheClearError(RuntimeException exception, Cache cache) {

    }
    };
    }


    @Bean
    public RedisTemplate<String,Object> redisTemplate(JedisConnectionFactory connectionFactory){

    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
    redisTemplate.setConnectionFactory(connectionFactory);
    redisTemplate.setKeySerializer(new StringRedisSerializer());
    redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
    return redisTemplate;
    }


    }
  5. 测试类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    package com.zzwtec.cache.demo;

    import com.zzwtec.cache.demo.model.User;
    import com.zzwtec.cache.demo.service.UserService;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;

    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = CacheDemoApplication.class,webEnvironment = SpringBootTest.WebEnvironment.NONE)
    public class CacheDemoApplicationTests {

    @Autowired
    private UserService userService;


    @Test
    public void testSaveUser(){
    User user = new User();
    user.setId("test-user");
    user.setEmail("[email protected]");
    user.setName("admin");
    userService.saveUser(user);


    }

    @Test
    public void testFindUser(){

    User userById = userService.findUserById("test-user");
    System.out.println(userById);
    }

    @Test
    public void testDeleteUser(){
    userService.deleteUserById("test-user");
    }


    @Test
    public void testUpdateUser(){
    User user = new User();
    user.setId("test-user");
    user.setName("adminUpdate");
    user.setEmail("[email protected]");
    userService.updateUserById(user);
    }

    }
  6. 配置文件

    1
    2
    3
    4
    spring:
    redis:
    host: 192.168.3.11
    port: 6379

五、结论#

使用起来简单吧??没错没有什么复杂的用法,就这样用.多跑跑case观察一下.就理解了.但有些小细节需要注意,后面再进行介绍,太晚了,累了,睡觉了.

感谢您的阅读,本文由 Onew 版权所有。如若转载,请注明出处:Onew(https://onew.me/2018/06/18/spring-data-cache/
jenkins部署hexo找不到hexo命令问题
kvm上安装win7