Spring boot 2.0的Redis缓存应用

范培忠 2018-04-18

  Spring Boot2.0.0.RELEASE在2018年3月1日正式发布。2.0下对Redis的使用与之前略有不同。具体实现如下:

        一、Maven依赖和配置

        添加3个依赖:


    org.springframework.boot
    spring-boot-starter-data-redis



    org.apache.commons
    commons-pool2
    2.5.0



    com.alibaba
    fastjson
    1.2.47

        application.yml配置:

spring:
    redis:
      #数据库索引
      database: 0
      host: 127.0.0.1
      port: 6379
      password: 123
      lettuce:
        pool:
          #最大连接数
          max-active: 8
          #最大阻塞等待时间(负数表示没限制)
          max-wait: -1
          #最大空闲
          max-idle: 8
          #最小空闲
          min-idle: 0
      #连接超时时间
      timeout: 10000

        fastjson.properties配置:

        本配置是为了解决在1.2.24后因修复漏洞导致的autotype is not support错误。

        具体解决办法为声明fastjson.properties文件,将需要打包的类设置白名单等,如下代码所示。

        可参考官方通告:https://github.com/alibaba/fastjson/wiki/enable_autotype

fastjson.parser.autoTypeAccept=cn.fanpz.springbootdemoredis3.domain.entity.User

        二、自定义序列化器

        若要实现对象的缓存,最好定义自己的序列化和反序列化器。使用阿里的fastjson来实现的比较多。

package cn.fanpz.springbootdemoredis3.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

import java.nio.charset.Charset;

public class FastJsonRedisSerializer implements RedisSerializer {
    private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
    private Class clazz;

    public FastJsonRedisSerializer(Class clazz) {
        super();
        this.clazz = clazz;
    }

    @Override
    public byte[] serialize(T t) throws SerializationException {
        if (null == t) {
            return new byte[0];
        }
        return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
    }

    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        if (null == bytes || bytes.length <= 0) {
            return null;
        }
        String str = new String(bytes, DEFAULT_CHARSET);
        return (T) JSON.parseObject(str, clazz);
    }
}

        三、添加RedisConfig配置

        在RedisConfig类里定义RedisTemplate的bean和Redis的CacheManager。

package cn.fanpz.springbootdemoredis3.config;

import cn.fanpz.springbootdemoredis3.util.FastJsonRedisSerializer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
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.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@EnableCaching
@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
public class RedisConfig extends CachingConfigurerSupport {

    @Bean(name = "redisTemplate")
    @SuppressWarnings("unchecked")
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate template = new RedisTemplate<>();

        //使用fastjson序列化
        FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class);
        // value值的序列化采用fastJsonRedisSerializer
        template.setValueSerializer(fastJsonRedisSerializer);
        template.setHashValueSerializer(fastJsonRedisSerializer);
        // key的序列化采用StringRedisSerializer
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());

        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    /*@Bean
    @ConditionalOnMissingBean(StringRedisTemplate.class)
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }*/

    //缓存管理器
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager
                .RedisCacheManagerBuilder
                .fromConnectionFactory(redisConnectionFactory);
        return builder.build();
    }

}

        四、定义用于测试的User类和UserService

        User类:

package cn.fanpz.springbootdemoredis3.domain.entity;

import java.io.Serializable;

public class User implements Serializable {

    private static final long serialVersionUID = -1L;

    private String username;
    private Integer age;

    public User(String username, Integer age) {
        this.username = username;
        this.age = age;
    }

    //getter和setter省略

}

        UserService:

package cn.fanpz.springbootdemoredis3.service.impl;

import cn.fanpz.springbootdemoredis3.domain.entity.User;
import cn.fanpz.springbootdemoredis3.service.UserService;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
    @Override
    @Cacheable(value = "user", key = "'user_'+#username")
    public User getUser(String username) {
        System.out.println(username + "进入实现类获取数据!");
        return new User("Ttomm", 22);
    }
}

        五、编写测试类

package cn.fanpz.springbootdemoredis3;

import cn.fanpz.springbootdemoredis3.domain.entity.User;
import cn.fanpz.springbootdemoredis3.service.UserService;
import org.junit.Assert;
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.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

@SuppressWarnings("unchecked")
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootDemoRedis3ApplicationTests {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private UserService userService;

    @Test
    //直接使用redisTemplate存取字符串
    public void setAndGet() {
        redisTemplate.opsForValue().set("test:set", "testValue1");
        Assert.assertEquals("testValue1", redisTemplate.opsForValue().get("test:set"));
    }

    @Test
    //直接使用redisTemplate存取对象
    public void setAndGetAUser() {
        User user = new User("Tom", 10);
        redisTemplate.opsForValue().set("test:setUser", user);
        Assert.assertEquals(user.getUsername(), ((User) redisTemplate.opsForValue().get("test:setUser")).getUsername());
    }

    @Test
    //使用Redis缓存对象,getUser只会被调用一次
    public void testCache() {
        User user;
        user = userService.getUser("Ttomm");
        user = userService.getUser("Ttomm");
        user = userService.getUser("Ttomm");
    }
}

        六、执行效果

        testCache()的执行效果如下,可见后台日志显示方法仅被实际调用了一次,缓存成功:

Spring boot 2.0的Redis缓存应用_第1张图片

你可能感兴趣的:(Java后端)