Spring boot 2.0的Redis快取應用
阿新 • • 發佈:2019-02-14
範培忠 2018-04-18
Spring Boot2.0.0.RELEASE
在2018年3月1日正式釋出。2.0下對Redis的使用與之前略有不同。具體實現如下:
一、Maven依賴和配置
新增3個依賴:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!--spring2.0整合redis所需common-pool2--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.5.0</version> </dependency> <!-- 將作為Redis物件序列化器 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.47</version> </dependency>
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檔案,將需要打包的類設定白名單等,如下程式碼所示。
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<T> implements RedisSerializer<T> {
private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
private Class<T> clazz;
public FastJsonRedisSerializer(Class<T> 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<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> 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()的執行效果如下,可見後臺日誌顯示方法僅被實際呼叫了一次,快取成功: