支持redis单机或集群缓存

This commit is contained in:
xlongwei 2019-09-27 03:28:35 +08:00
parent cf211fa19c
commit 86dd0b3be6
7 changed files with 242 additions and 14 deletions

View File

@ -23,6 +23,12 @@
<artifactId>spring-boot-starter-thymeleaf</artifactId> <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency> </dependency>
<!-- 支持redis缓存 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- spring-boot-devtools --> <!-- spring-boot-devtools -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>

View File

@ -0,0 +1,68 @@
package com.ruoyi.web.core.config;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import java.time.Duration;
import java.util.Map;
@EnableCaching
@Configuration
public class CacheConfig {
@Autowired(required = false)
RedisConnectionFactory redisConnectionFactory;
//默认超时设置1小时
@Value("${spring.redis.defaultExpiration:3600}")
Duration defaultExpiration;
//自定义部分缓存的超时
@Value("${spring.redis.expires}")
String expires = "{}";
@Bean
public CacheManager cacheManager() {
if (redisConnectionFactory != null) {
try {
//配置有redis standalone或cluster并且能正常连接时才启用redis缓存
redisConnectionFactory.getConnection().ping();
System.err.println("using redis cache manager");
RedisCacheManager redisCacheManager = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults
(RedisCacheConfiguration.defaultCacheConfig().entryTtl(defaultExpiration))
.withInitialCacheConfigurations(Maps.transformValues(JSON.parseObject(expires, Map.class), d ->
RedisCacheConfiguration
.defaultCacheConfig().entryTtl(Duration.ofSeconds(Long.valueOf(d.toString())))))
.transactionAware().build();
return redisCacheManager;
} catch (Exception e) {
System.err.println("fail to connect to redis");
}
}
EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean();
ehCacheManagerFactoryBean.setConfigLocation(new ClassPathResource("classpath:ehcache/ehcache-shiro.xml"));
ehCacheManagerFactoryBean.setShared(true);
return new EhCacheCacheManager(ehCacheManagerFactoryBean.getObject()) {
@Override
protected Cache getMissingCache(String name) {
Cache cache = super.getMissingCache(name);
if (cache == null) {
//使用default配置克隆缓存
getCacheManager().addCacheIfAbsent(name);
cache = super.getCache(name);
}
return cache;
}
};
}
}

View File

@ -69,6 +69,22 @@ spring:
restart: restart:
# 热部署开关 # 热部署开关
enabled: true enabled: true
# redis配置
redis:
host: localhost
port: 6379
password:
timeout: 1500ms
# redis连接池配置
jedis:
pool:
min-idle: 1
# redis集群配置逗号分隔多个host:port
# cluster:
# nodes: 127.0.0.1:6381,127.0.0.1:6382
# 默认缓存超时1小时启动时可初始化多个缓存并指定超时N秒
defaultExpiration: 1h
expires: '{ "loginRecordCache": "600" }'
# MyBatis # MyBatis
mybatis: mybatis:

View File

@ -6,6 +6,8 @@ import java.io.InputStream;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import javax.servlet.Filter; import javax.servlet.Filter;
import com.ruoyi.framework.shiro.cache.SpringCacheManagerWrapper;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.shiro.cache.ehcache.EhCacheManager; import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64; import org.apache.shiro.codec.Base64;
@ -17,8 +19,10 @@ import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager; import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie; import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
@ -93,25 +97,29 @@ public class ShiroConfig
@Value("${shiro.user.unauthorizedUrl}") @Value("${shiro.user.unauthorizedUrl}")
private String unauthorizedUrl; private String unauthorizedUrl;
@Autowired(required = false)
private CacheManager cacheManager;
/** /**
* 缓存管理器 使用Ehcache实现 * 缓存管理器 使用Spring CacheManager或Ehcache实现
*/ */
@Bean @Bean
public EhCacheManager getEhCacheManager() public org.apache.shiro.cache.CacheManager getEhCacheManager()
{ {
if(cacheManager != null){
return new SpringCacheManagerWrapper(cacheManager);
}else {
net.sf.ehcache.CacheManager cacheManager = net.sf.ehcache.CacheManager.getCacheManager("ruoyi"); net.sf.ehcache.CacheManager cacheManager = net.sf.ehcache.CacheManager.getCacheManager("ruoyi");
EhCacheManager em = new EhCacheManager(); EhCacheManager em = new EhCacheManager();
if (StringUtils.isNull(cacheManager)) if (StringUtils.isNull(cacheManager)) {
{
em.setCacheManager(new net.sf.ehcache.CacheManager(getCacheManagerConfigFileInputStream())); em.setCacheManager(new net.sf.ehcache.CacheManager(getCacheManagerConfigFileInputStream()));
return em; return em;
} } else {
else
{
em.setCacheManager(cacheManager); em.setCacheManager(cacheManager);
return em; return em;
} }
} }
}
/** /**
* 返回配置文件流 避免ehcache配置文件一直被占用无法完全销毁项目重新部署 * 返回配置文件流 避免ehcache配置文件一直被占用无法完全销毁项目重新部署
@ -142,7 +150,7 @@ public class ShiroConfig
* 自定义Realm * 自定义Realm
*/ */
@Bean @Bean
public UserRealm userRealm(EhCacheManager cacheManager) public UserRealm userRealm(org.apache.shiro.cache.CacheManager cacheManager)
{ {
UserRealm userRealm = new UserRealm(); UserRealm userRealm = new UserRealm();
userRealm.setCacheManager(cacheManager); userRealm.setCacheManager(cacheManager);

View File

@ -0,0 +1,22 @@
package com.ruoyi.framework.shiro.cache;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
/** 包装Spring CacheManager为Shiro CacheManager */
public class SpringCacheManagerWrapper implements CacheManager {
private org.springframework.cache.CacheManager cacheManager;
public SpringCacheManagerWrapper(org.springframework.cache.CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
@Override
public <K, V> Cache<K, V> getCache(String name) throws CacheException {
org.springframework.cache.Cache springCache = cacheManager.getCache(name);
return new SpringCacheWrapper(springCache);
}
}

View File

@ -0,0 +1,106 @@
package com.ruoyi.framework.shiro.cache;
import net.sf.ehcache.Ehcache;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.cache.support.SimpleValueWrapper;
import java.util.*;
/** 包装Spring Cache为Shiro Cache */
public class SpringCacheWrapper implements Cache {
private org.springframework.cache.Cache springCache;
private boolean isEhcache;
private Set<Object> keys;
SpringCacheWrapper(org.springframework.cache.Cache springCache) {
this.springCache = springCache;
this.isEhcache = springCache.getNativeCache() instanceof Ehcache;
if (!this.isEhcache) {
keys = new HashSet<>();
}
}
@Override
public Object get(Object key) throws CacheException {
Object value = springCache.get(isEhcache ? key : key.toString());
if (value instanceof SimpleValueWrapper) {
return ((SimpleValueWrapper) value).get();
}
return value;
}
@Override
public Object put(Object key, Object value) throws CacheException {
springCache.put(isEhcache ? key : key.toString(), value);
if (!isEhcache) {
keys.add(key.toString());
}
return value;
}
@Override
public Object remove(Object key) throws CacheException {
springCache.evict(isEhcache ? key : key.toString());
if (!isEhcache) {
keys.remove(key.toString());
}
return null;
}
@Override
public void clear() throws CacheException {
springCache.clear();
if (!isEhcache) {
keys.clear();
}
}
@Override
public int size() {
if (isEhcache) {
Ehcache ehcache = (Ehcache) springCache.getNativeCache();
return ehcache.getSize();
} else {
return keys.size();
}
}
@Override
public Set keys() {
if (isEhcache) {
Ehcache ehcache = (Ehcache) springCache.getNativeCache();
return new HashSet<Object>(ehcache.getKeys());
} else {
return keys;
}
}
@Override
public Collection values() {
if (isEhcache) {
Ehcache ehcache = (Ehcache) springCache.getNativeCache();
List keys = ehcache.getKeys();
if (!CollectionUtils.isEmpty(keys)) {
List<Object> values = new ArrayList<>(keys.size());
for (Object key : keys) {
Object value = get(key);
if (value != null) {
values.add(value);
}
}
return Collections.unmodifiableList(values);
} else {
return Collections.emptyList();
}
} else {
List<Object> values = new ArrayList<>(keys.size());
for (Object key : keys) {
Object value = get(key);
values.add(value);
}
return Collections.unmodifiableCollection(values);
}
}
}

View File

@ -92,6 +92,8 @@ public class OnlineSessionDAO extends EnterpriseCacheSessionDAO
} }
// 更新上次同步数据库时间 // 更新上次同步数据库时间
onlineSession.setAttribute(LAST_SYNC_DB_TIMESTAMP, onlineSession.getLastAccessTime()); onlineSession.setAttribute(LAST_SYNC_DB_TIMESTAMP, onlineSession.getLastAccessTime());
// 保存数据更新到缓存避免每次都同步到数据库
cache(onlineSession, onlineSession.getId());
// 更新完后 重置标识 // 更新完后 重置标识
if (onlineSession.isAttributeChanged()) if (onlineSession.isAttributeChanged())
{ {