使用场景
- 为shiro认证与授权时高频的sql查询配置上缓存
- shiro有缓存管理器的配置入口,因为做了一些调整,所以要手动配置.
引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.6</version>
</dependency>
使用
- 总体上分三步
1.添加ehcache.xml文件并配置
2.添加EhCacheConfig类
3.通过注解使用
- ehcache.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false" monitoring="autodetect"
dynamicConfig="true" >
<diskStore path="java.io.tmpdir/ehcache"/>
<defaultCache
maxElementsInMemory="50000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="3600"
overflowToDisk="true"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
/>
<!-- 认证与授权用的缓存 设置 -->
<cache name="shiro_cache"
maxElementsInMemory="50000"
eternal="true"
clearOnFlush="false"
overflowToDisk="true"
diskSpoolBufferSizeMB="1024"
maxElementsOnDisk="100000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LFU"
transactionalMode="off">
</cache>
</ehcache>
<!--
maxElementsInMemory="10000" //Cache中最多允许保存的数据对象的数量
external="false" //缓存中对象是否为永久的,如果是,超时设置将被忽略,对象从不过期
timeToLiveSeconds="3600" //缓存的存活时间,从开始创建的时间算起
timeToIdleSeconds="3600" //多长时间不访问该缓存,那么ehcache 就会清除该缓存
1、timeToLiveSeconds的定义是:以创建时间为基准开始计算的超时时长;
2、timeToIdleSeconds的定义是:在创建时间和最近访问时间中取出离现在最近的时间作为基准计算的超时时长;
3、如果仅设置了timeToLiveSeconds,则该对象的超时时间=创建时间+timeToLiveSeconds,假设为A;
4、如果没设置timeToLiveSeconds,则该对象的超时时间=min(创建时间,最近访问时间)+timeToIdleSeconds,假设为B;
5、如果两者都设置了,则取出A、B最少的值,即min(A,B),表示只要有一个超时成立即算超时。
overflowToDisk="true" //内存不足时,是否启用磁盘缓存
diskSpoolBufferSizeMB //设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区
maxElementsOnDisk //硬盘最大缓存个数
diskPersistent //是否缓存虚拟机重启期数据The default value is false
diskExpiryThreadIntervalSeconds //磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy="LRU" //当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
clearOnFlush //内存数量最大时是否清除
maxEntriesLocalHeap="0" //堆内存中最大缓存对象数,0没有限制
maxEntriesLocalDisk="1000" //硬盘最大缓存个数。
-->
- 文件应该放到项目resources目录下,如果调整了位置或者文件名称,需要在配置文件中指定.
- 可以根据需要增加cache 标签,一个cache 标签可以理解为一个Map.缓存储存时需要指定cache 的名称
EhCacheConfig 类
import net.sf.ehcache.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;
/**
* ehcache配置
*/
@Configuration
@EnableCaching
public class EhCacheConfig {
/**
* EhCache的配置
*/
@Bean
public EhCacheCacheManager cacheManager(CacheManager cacheManager) {
return new EhCacheCacheManager(cacheManager);
}
/**
* EhCache的配置
*/
@Bean
public EhCacheManagerFactoryBean ehcache() {
EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean();
ehCacheManagerFactoryBean.setConfigLocation(new ClassPathResource("ehcache.xml"));
return ehCacheManagerFactoryBean;
}
}
- 主要做的就是创建实例和注入Bean
- 使用注解前创建几个常量类.非必须
/**
* 所有缓存名称的集合
*
*/
public interface CacheName {
/**
* 用于进行shiro认证和授权的缓存 应与xml文件一致
*/
String SHIRO_CACHE = "shiro_cache";
}
/**
* 缓存标识前缀
*/
public interface CacheKey {
/**
* 用于通过userid获取角色的id和名称集合
*/
String ROLES_BY_USERID_ = "roles_by_userid_";
/**
* 获取用于认证的用户信息
*/
String USER_AUTH_ = "user_auth_";
}
ehcahe的注解 见https://www.cnblogs.com/fashflying/p/6908028.html
在通过账号获取用户的方法加上注解,该方法是进行认证时执行的查询方法
@Cacheable(value = CacheName.SHIRO_CACHE ,key = "'" + CacheKey.USER_AUTH_ + "'+#account")
@Override
public BaseUser getByAccount(String account){
return userDao.getByAccount(account);
}
- 在通过用户id获取用户角色信息的接口增加注解.
@Cacheable(value = CacheName.SHIRO_CACHE ,key = "'" + CacheKey.ROLES_BY_USERID_ + "'+#userId")
List<Map<String,Object>> getRoleIdAndNameByUserId(Long userId);
- 缓存的删除
- 缓存的删除一般通过@CacheEvict实现,用于场景的限制,使用了手动删除的方式.
- 场景:在用户信息变更时,移除认证查询时的缓存,在用户角色信息变更时,移除授权查询的缓存.
@Autowired
EhCacheCacheManager ehCacheCacheManager;
public Long addOrEdit(BaseUser model, RequestPara para){
BaseUser user_temp= getByAccount(model.getAccount());
//如果user_temp不为空,但id一样,说明是进行不改名字的编辑,不视为用户名存在
Assert.isTrue(user_temp==null||user_temp.getId().equals(model.getId()),"该账号已存在");
Long id=null;
if(ModelUtil.isNew(model)){
if(!StringUtils.hasText(model.getName())){
model.setName(model.getAccount());
}
super.save(model);
}
id= model.getId();
Assert.isTrue(id!=null,"添加用户失败");
//修改密码
String is_update_password=WebUtils.get("is_update_password");
if(YesOrNotEnum.Y.getCodeTest().equals(is_update_password)){
//密码md5加密后,加盐加密
String md5Password= null;
try {
md5Password = Md5Salt.sec(String.valueOf(id),model.getPassword());
} catch (Exception e) {
throw new ServiceException(MsgEnum.ENCRYPT_ERROR);
}
model.setPassword(md5Password);
}
super.updateById(model);
//删除shiro_cache内的 用户信息缓存
CacheManager cacheManager = ehCacheCacheManager.getCacheManager();
Cache cache = cacheManager.getCache(CacheName.SHIRO_CACHE);
cache.remove(CacheKey.USER_AUTH_+model.getAccount());
//设置用户的角色
String[] role_ids=para.getArray("role_ids");
if(role_ids!=null){
Long[] role_ids_int= (Long[]) ConvertUtils.convert(role_ids, Long.class);
saveRoleInfo(id,role_ids_int);
//移除角色信息缓存
cache.remove(CacheKey.ROLES_BY_USERID_+id);
}
return model.getId();
}