Springboot整合(8)——Redis
Springboot整合(8)——Redis
0. 搭建redis环境,可参考我之前的文章:用docker搭建redis
1. pom中增加redis依赖
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2. 在application.yml中spring的节点下(跟datasource同一层)增加redis配置
#Redis配置
redis:
database: 0
host: 192.168.59.103
port: 6379
pool:
max-idle: 8
min-idle: 0
max-active: 8
max-wait: -1
3. 编写redis序列化对象类
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.serializer.support.DeserializingConverter;
import org.springframework.core.serializer.support.SerializingConverter;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
/**
* redis序列化对象
*/
publicclass RedisObjectSerializer implements RedisSerializer<Object> {
private Converter<Object, byte[]> serializer = new SerializingConverter();
private Converter<byte[], Object> deserializer = new DeserializingConverter();
staticfinalbyte[] EMPTY_ARRAY = newbyte[0];
public Object deserialize(byte[] bytes) {
if (isEmpty(bytes)) {
returnnull;
}
try {
returndeserializer.convert(bytes);
} catch (Exception ex) {
thrownew SerializationException("Cannot deserialize", ex);
}
}
publicbyte[] serialize(Object object) {
if (object == null) {
returnEMPTY_ARRAY;
}
try {
returnserializer.convert(object);
} catch (Exception ex) {
returnEMPTY_ARRAY;
}
}
privateboolean isEmpty(byte[] data) {
return (data == null || data.length == 0);
}
}
4. 编写redis配置类RedisCacheConfig
/**
* Redis缓存配置类
*/
@Configuration
@EnableCaching
publicclass RedisCacheConfig extends CachingConfigurerSupport {
// 自定义缓存key生成策略
@Bean
public KeyGenerator keyGenerator() {
returnnew KeyGenerator() {
@Override
public Object generate(Object target, java.lang.reflect.Method method, Object... params) {
StringBuffer sb = new StringBuffer();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
if (obj == null) {
continue;
}
sb.append(obj.toString());
}
returnsb.toString();
}
};
}
// 缓存管理器
@Bean
public CacheManager cacheManager(@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
// 设置缓存过期时间
cacheManager.setDefaultExpiration(1800);
returncacheManager;
}
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
template.setConnectionFactory(factory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new RedisObjectSerializer ());
returntemplate;
}
}
5. 使用缓存有2种方法,一种是直接在Controller里使用注解的方式,另一种是自已手动读取写入缓存,前者更加方便,后者更加灵活,根据实际需求选择具体使用哪种,下面将2中方法分别说明
5.1 在Controller中使用注解方式使用缓存
@Cacheable 从缓存读取数据
@CacheEvict 清除缓存
示例:
① 访问http://localhost:8088/KnowledgeIsland/user/cacheList,首次后台会打印sql,再次访问就不会打印sql,从redis里读取
② 进入http://localhost:8088/KnowledgeIsland/user/add,添加一个user,查看redis,会看到redis里user的缓存已经被清除,再次访问http://localhost:8088/KnowledgeIsland/user/cacheList,又会去数据库查询
5.2 自己编码实现读取写入缓存
① 编写操作缓存的工具类
/**
* Cache工具类
*/
publicclass CacheUtil {
privatestatic Logger logger = LoggerFactory.getLogger(CacheUtil.class);
privatestatic CacheManager cacheManager = SpringUtil.getBean(CacheManager.class);
//是否开启缓存
privatestaticbooleanenableCache = true;
/**
* 获取缓存
*
* @param cacheName
* @param key
* @return
*/
publicstatic Object get(String cacheName, String key) {
if (!enableCache) {
returnnull;
}
ValueWrapper valueWrapper = getCache(cacheName).get(key);
if (valueWrapper == null) {
returnnull;
}
return getCache(cacheName).get(key).get();
}
/**
* 获取缓存
*
* @param cacheName
* @param key
* @param defaultValue
* @return
*/
publicstatic Object get(String cacheName, String key, Object defaultValue) {
if (!enableCache) {
returndefaultValue;
}
Object value = get(cacheName, key);
returnvalue != null ? value : defaultValue;
}
/**
* 写入缓存
*
* @param cacheName
* @param key
* @param value
*/
publicstaticvoid put(String cacheName, String key, Object value) {
if (!enableCache) {
return;
}
getCache(cacheName).put(key, value);
}
/**
* 从缓存中移除
*
* @param cacheName
* @param key
*/
publicstaticvoid remove(String cacheName, String key) {
if (!enableCache) {
return;
}
getCache(cacheName).evict(key);
}
/**
* 从缓存中移除所有
*
* @param cacheName
*/
publicstaticvoid removeAll(String cacheName) {
if (!enableCache) {
return;
}
getCache(cacheName).clear();
logger.info("清理缓存: {} => {}", cacheName);
}
/**
* 获得一个Cache,没有则显示日志。
*
* @param cacheName
* @return
*/
privatestatic Cache getCache(String cacheName) {
Cache cache = cacheManager.getCache(cacheName);
if (cache == null) {
thrownew RuntimeException("当前系统中没有定义“" + cacheName + "”这个缓存。");
}
returncache;
}
}
注:该类引用了一个SpringUtil类,该类的作用是可以让那些没有注册为spring component的普通类调用spring bean,代码如下:
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* 普通类调用Spring bean对象:说明: 1、此类需要放到App.java同包或者子包下才能被扫描,否则失效。
*/
@Component
publicclass SpringUtil implements ApplicationContextAware {
privatestatic ApplicationContext applicationContext = null;
@Override
publicvoid setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringUtil.applicationContext == null) {
SpringUtil.applicationContext = applicationContext;
}
System.out.println("---------------------------------------------------------------------");
System.out.println("---------------------------------------------------------------------");
System.out.println(
"---------------com.kfit.base.util.SpringUtil------------------------------------------------------");
System.out.println(
"========ApplicationContext配置成功,在普通类可以通过调用SpringUtils.getAppContext()获取applicationContext对象,applicationContext="
+ SpringUtil.applicationContext + "========");
System.out.println("---------------------------------------------------------------------");
}
// 获取applicationContext
publicstatic ApplicationContext getApplicationContext() {
returnapplicationContext;
}
// 通过name获取 Bean.
publicstatic Object getBean(String name) {
return getApplicationContext().getBean(name);
}
// 通过class获取Bean.
publicstatic <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
// 通过name,以及Clazz返回指定的Bean
publicstatic <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
}
② 调用工具类操作缓存,操作逻辑可放在任何地方,本文示例放在UserService里。put,remove,clear,完全自由控制(本处只示例get和put)
controller层调用代码不变
③访问http://localhost:8088/KnowledgeIsland/user/list测试
6. 特别注意的地方,所有放入redis的对象,需要实现Serializable接口。将对象类型数据放入redis,本文采用的方法是将对象序列化之后放入。另一种方法是,将对象全部转为json字符串,然后再放入,拿出来的时候再转回来。