SpringBoot--使用redis缓存(1)

本文主要记录对SpringBoot集成redis缓存功能的学习总结。采用扩展Spring的缓存功能的方式。

一、Spring缓存注解
(1)@Cacheable
主要针对方法配置,能能够根据方法的请求参数对其结果进行缓存。
主要参数:
1)value:缓存的名称,必须至少指定一个。例如@Cacheable(value="cache")、@Cacheable(value={"cache1","cache2"})
2)key:缓存的key,需要按照spel表达式进行指定,当然也可以不指定,那么就按照缺省的所有参数进行组合。例如@Cacheable(value="cache",key="#userName")
3)condition:缓存的条件,可以为空,使用SPEL编写,返回布尔值,只有为true的时候才进行缓存。例如:@Cacheable(value="cache",key="#userName",condition="#userName.length>5")
(2)@CachePut
主要针对方法配置,能够根据方法的请求参数对其结果进行缓存。与@Cacheable不同的是,它每次都会处罚真实的方法调用。
主要参数:
1)value:缓存的名称,至少应该指定一个。例如:@Cacheable(value="cache")、@Cacheable(value={"cache1","cache2"})
2)key:缓存的key,需要按照spel表达式进行指定,当然也可以不指定,那么就按照缺省的所有参数进行组合。例如@Cacheable(value="cache",key="#userName")
3)condition:缓存的条件,可以为空,使用SPEL编写,返回布尔值,只有为true的时候才进行缓存。例如:@Cacheable(value="cache",key="#userName",condition="#userName.length>5")
(3)@CacheEvict 
主要针对方法配置,能够根据一定的条件对缓存进行清空。
主要参数
1)value:缓存的名称,至少应该指定一个。例如:@Cacheable(value="cache")、@Cacheable(value={"cache1","cache2"})
2)key:缓存的key,需要按照spel表达式进行指定,当然也可以不指定,那么就按照缺省的所有参数进行组合。例如@Cacheable(value="cache",key="#userName")
3)condition:缓存的条件,可以为空,使用SPEL编写,返回布尔值,只有为true的时候才进行缓存。例如:@Cacheable(value="cache",key="#userName",condition="#userName.length>5")
4)allEntries:是否清空所有缓存的内容,默认为false,如果为true,调用该方法后将清空所有的redis缓存。
5)beforeInvocation:是否在方法执行前就清空,缺省为false,如果指定为true,则在方法还没有执行前就会清空缓存。当然如果抛出异常,则不会清空缓存。

二、具体实现过程

注意:本文的示例工程是基于已经集成好了jpa的前提进行搭建的。

(1)需要添加的maven依赖

        <!--引入缓存-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>

        <!--支持redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-redis</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
(2)配置redis缓存配置文件

package com.liutao.config;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.lang.reflect.Method;

/**
 * redis缓存配置,采用继承的方式来改变Spring的缓存策略。
 *
 * 注意:这里可以不用继承CachingConfigurerSupport,也就是一个普通的RedisCacheConfig亦可以。
 * 如果要从新实现key的生成策略,只要这里修改KeyGenerator就可以,其他地方不用修改。
 * 如果使用普通类,那么在使用@Cacheable的时候需要指定KeyGenarator的名字。
 * @author LIUTAO
 * @version 2017/5/15
 * @see
 */
@Configuration
@EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport {

    /**
     * 缓存管理器
     * @param redisTemplate
     * @return
     */
    @Bean
    public CacheManager cacheManager(RedisTemplate<?,?> redisTemplate){
        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);

        //设置默认过期时间
        cacheManager.setDefaultExpiration(60);
        return cacheManager;
    }

    /**
     * redis模板操作类
     * 虽然CacheManager也能获取到Cache对象,但是操作起来不灵活
     *
     * @param factory
     * @return
     */
    @Bean
    public RedisTemplate<String,String> redisTemplate(RedisConnectionFactory factory){
        RedisTemplate<String,String> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(redisSerializer);
        redisTemplate.setHashKeySerializer(redisSerializer);
        return redisTemplate;
    }

    /**
     * 自定义Key
     * 此方法会根据类名+方法名+所有参数的值生成一个唯一的key,即使@Cacheable中的value一样,key也会不一样。
     * @return
     */
    @Bean
    public KeyGenerator keyGenerator() {
        System.out.println("RedisCacheConfig.keyGenerator()");
        return new KeyGenerator() {
            @Override
            public Object generate(Object o, Method method, Object... objects) {
                StringBuilder sb = new StringBuilder();
                sb.append(o.getClass().getName());
                sb.append(method.getName());
                for (Object obj : objects) {
                    sb.append(obj.toString());
                }
                System.out.println("keyGenerator=" + sb.toString());
                return sb.toString();
            }
        };
    }
}

(3)缓存测试方法

package com.liutao.service.impl;

import com.liutao.dao.UserDao;
import com.liutao.entity.User;
import com.liutao.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
/**
 * 用户服务层
 *
 * @author LIUTAO
 * @version 2017/3/29
 * @see
 * @since
 */






@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserDao userDao;
    private Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    /**
     * 执行缓存
     * @param id
     * @return
     */
    @Cacheable(value="user",keyGenerator = "keyGenerator")                //缓存,这里没有指定Key
    @Override
    public User findById(Integer id) {
        logger.debug("the data coming from database is :"+id);
        return userDao.findOne(id);
    }

    /**
     * 清空缓存
     * @param id
     */
    @CacheEvict(value="user",allEntries = true)
    @Override
    public void deleteFromCache(Integer id) {
        logger.debug("delete from cache");
    }
}

(4)缓存测试Controller

package com.liutao.controller;

import com.liutao.entity.User;
import com.liutao.service.UserService;
import com.wordnik.swagger.annotations.Api;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

/**
 * 用户控制层
 *
 * @author LIUTAO
 * @version 2017/3/29
 * @see
 * @since
 */
@Controller
@Api(value = "test")
@RequestMapping("/liutao/v1")
public class UserController {

    private Logger logger = LoggerFactory.getLogger(UserController.class);

    @Autowired
    private UserService userServiceImpl;

    @GetMapping("/user")
    public @ResponseBody String test(){
        User userOfload = userServiceImpl.findById(1);
        logger.debug("userOfload:"+userOfload);
        User userOfCached = userServiceImpl.findById(1);
        logger.debug("userOfCached:"+userOfCached);
        userOfload = userServiceImpl.findById(2);
        logger.debug("userOfload2:"+userOfload);
        return "ok";

    }

    @DeleteMapping("/userOfCache")
    public @ResponseBody String delete(Integer id){
        userServiceImpl.deleteFromCache(id);
        return "ok";
    }

    @GetMapping("user2")
    public @ResponseBody String testTwo(){
        logger.debug("UserController.testTwo()");
        return "ok";
    }
}

(5)测试结果

首次调用如下接口:

http://localhost:8080/liutao/v1/user
运行日志:

keyGenerator=com.liutao.service.impl.UserServiceImplfindById1
keyGenerator=com.liutao.service.impl.UserServiceImplfindById1
2017-05-15 15:16:42.178 [http-nio-8080-exec-7] DEBUG com.liutao.service.impl.UserServiceImpl - the data coming from database is :1
2017-05-15 15:16:42.190 [http-nio-8080-exec-7] DEBUG com.liutao.controller.UserController - userOfload:User{name='张三丰', age=45, password='zsf123', id=1}
keyGenerator=com.liutao.service.impl.UserServiceImplfindById1
2017-05-15 15:16:42.191 [http-nio-8080-exec-7] DEBUG com.liutao.controller.UserController - userOfCached:User{name='张三丰', age=45, password='zsf123', id=1}
keyGenerator=com.liutao.service.impl.UserServiceImplfindById2
keyGenerator=com.liutao.service.impl.UserServiceImplfindById2
2017-05-15 15:16:42.192 [http-nio-8080-exec-7] DEBUG com.liutao.service.impl.UserServiceImpl - the data coming from database is :2
2017-05-15 15:16:42.195 [http-nio-8080-exec-7] DEBUG com.liutao.controller.UserController - userOfload2:User{name='guanyuqq', age=54, password='gy123', id=2}

再次调用以上接口,运行日志:

keyGenerator=com.liutao.service.impl.UserServiceImplfindById1
2017-05-15 15:18:05.072 [http-nio-8080-exec-10] DEBUG com.liutao.controller.UserController - userOfload:User{name='张三丰', age=45, password='zsf123', id=1}
keyGenerator=com.liutao.service.impl.UserServiceImplfindById1
2017-05-15 15:18:05.073 [http-nio-8080-exec-10] DEBUG com.liutao.controller.UserController - userOfCached:User{name='张三丰', age=45, password='zsf123', id=1}
keyGenerator=com.liutao.service.impl.UserServiceImplfindById2
2017-05-15 15:18:05.073 [http-nio-8080-exec-10] DEBUG com.liutao.controller.UserController - userOfload2:User{name='guanyuqq', age=54, password='gy123', id=2}

根据以上的对比,可以看见,在第二次的调用中并没有进行Mysql数据库进行查询。但是当我们超过缓存时间(60)去从新调用以上接口的时候会发现从新进入数据库进行了查询,如果我们调用以下接口,就是清除了缓存。

http://localhost:8080/liutao/v1/userOfCache?id=1

详细代码请参考gitHub地址:SpringBoot--redis缓存1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值