Shiro自定义缓存,扩展Shiro缓存模块,只需要配置缓存即可实现Session共享

本文详细介绍了一种Shiro自定义缓存的实现方案,通过抽象缓存接口,实现Shiro与不同缓存系统的无缝集成,包括Redis和Ehcache,适用于分布式系统。

Shiro自定义缓存

之前在做Shiro集成的时候,辗转各个论坛,对于ehcache和redis集成太过繁琐,想尝试着将Shiro的缓存抽象出来,在不改变Shiro的前提下,达到缓存的可配置方案,那样对于项目而言可以更好的实现集群的部署。
于是就衍生了如下的设计:
一、设计方案
1.Shiro配置文件的修改
我们还是来介绍一下Shiro的自定义缓存吧,当有这个想法的时候,翻阅了各个地方的文档和demo最后发现Shiro是支持自定义缓存的,但需要集成AbstractCacheManager来实现

Shiro自定义缓存只需要在Shiro的配置文件中替换原有的cacheManager,
我便尝试着使用自己新建的cacheManager

<bean id="cacheManager" class="com.cn.contiy.system.shiro.entity.SMCacheManager" />

SpringBoot同理,修改代码而已。

2.自行实现的缓存类
当我们集成AbstractCacheManager后,我们会发现在AbstractCacheManager有一个抽象方法需要实现

 protected abstract Cache createCache(String s)
        throws CacheException;

显而易见,这个方法是Shiro的CacheManager用来创建缓存,所以,我们就需要在此处进行集成,这个先暂时不实现;
这个创建缓存的方法使用了一个返回值Cache,观察了一下是基于org.apache.shiro.cache.Cache接口的,所以,重点就是在此处怎样合理的使用org.apache.shiro.cache.Cache接口,以下便是心路历程

a.实现org.apache.shiro.cache.Cache接口
b.实现类实现createCache,并返回实现了org.apache.shiro.cache.Cache接口的实现类
c.在org.apache.shiro.cache.Cache接口的实现类中,封装缓存接口
d.分别使用Redis和Ehcache实现缓存接口
e.使用工厂类获取缓存
f.在项目启动时确定项目使用的缓存方式

SO,手术开始:
(1)创建通用缓存接口

public interface Cacher {
	public void set(String key, Object value);
	public Object get(String key);
	public void delete(String key);
	public Set<String> keys(String string);
	public Set<?> getAllValue(String keyPrefix);
	public Long dbSize();
}

接口的方法我就不描述了,一是因为懒,二是因为基本看英文能看懂是个什么玩意儿
(2)Cache工厂,切换缓存

public class CacherFactory {
	/** @desc 缓存工具 */
	public static Cacher cacher;

	@SuppressWarnings("static-access")
	public static void setAdpt(Object cacherAdpt) {
		cacher = (Cacher) cacherAdpt;
	}

}

定义了缓存工厂后,使用缓存就很容易了,只需要CacherFactory.cacher即可
(3)Redis缓存实现类

@Service("redisCacher")
@SuppressWarnings({ "unchecked", "rawtypes" })
public class RedisCacher implements Cacher {

	@Resource
	private org.springframework.data.redis.core.RedisTemplate redisTemplate;

	public void set(String key, Object value) {
		redisTemplate.opsForValue().set(key, value);
		// BoundValueOperations的理解对保存的值做一些细微的操作
		// BoundValueOperations boundValueOperations =
		// redisTemplate.boundValueOps(key);
	}

	public Object get(String key) {
		return redisTemplate.opsForValue().get(key);
	}

	
	public void delete(String key) {
		redisTemplate.delete(key);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.cn.contiy.system.cache.Cacher#keys(java.lang.String)
	 */
	@Override
	public Set<String> keys(String key) {
		return redisTemplate.keys(key + "*");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.cn.contiy.system.cache.Cacher#getAllValue(java.lang.String)
	 */
	@Override
	public Set<?> getAllValue(String keyPrefix) {
		Set<Object> list = new HashSet<Object>();
		ValueOperations v = redisTemplate.opsForValue();
		Set<String> keys = this.keys(keyPrefix);
		for (String string : keys) {
			list.add(v.get(string));
		}
		return list;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.cn.contiy.system.cache.Cacher#dbSize()
	 */
	@Override
	public Long dbSize() {
		return redisTemplate.getConnectionFactory().getConnection().dbSize();
	}

}

RedisCacher如上文所言,实现接口的方法,其余缓存也是一样
(4)实现org.apache.shiro.cache.Cache接口

@Service("shiroCache")
public class ShiroCache<K, V> implements Cache<K, V> {
	/**
	*这个是给Shiro的缓存Key进行分组标识,标识在缓存中以这个Key开头的都是Shiro的缓存
	*/
	private static final String KEY_PREFIX = "shiro_session:";

	/*
	 * 这个clear方法没做好,应该在cacher接口中定义,由缓存的实现类去实现
	 * 
	 * @see org.apache.shiro.cache.Cache#clear()
	 */
	@Override
	public void clear() throws CacheException {
		Set<String> keys = CacherFactory.cacher.keys(KEY_PREFIX);
		for (String string : keys) {
			CacherFactory.cacher.delete(string);
		}
	}

	private String getkey(String key) {
		return KEY_PREFIX + key;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.apache.shiro.cache.Cache#get(java.lang.Object)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public V get(K arg0) throws CacheException {
		return (V) CacherFactory.cacher.get(getkey(arg0.toString()));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.apache.shiro.cache.Cache#keys()
	 */
	@SuppressWarnings("unchecked")
	@Override
	public Set<K> keys() {
		return (Set<K>) CacherFactory.cacher.keys(KEY_PREFIX);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.apache.shiro.cache.Cache#put(java.lang.Object, java.lang.Object)
	 */
	@Override
	public V put(K arg0, V arg1) throws CacheException {
		CacherFactory.cacher.set(getkey(arg0.toString()), arg1);
		return arg1;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.apache.shiro.cache.Cache#remove(java.lang.Object)
	 */
	@Override
	public V remove(K arg0) throws CacheException {
		V previous = get(arg0);
		CacherFactory.cacher.delete(getkey(arg0.toString()));
		return previous;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.apache.shiro.cache.Cache#size()
	 */
	@Override
	public int size() {
		Long longSize = CacherFactory.cacher.dbSize();
		return longSize.intValue();
	}

	/*
	 * 因为缓存中只要Shiro的key,免不了这一步
	 * 
	 * @see org.apache.shiro.cache.Cache#values()
	 */
	@SuppressWarnings("unchecked")
	@Override
	public Collection<V> values() {
		Collection<V> v = new HashSet<>();
		Set<String> keys = CacherFactory.cacher.keys(KEY_PREFIX);
		for (String string : keys) {
			if (CacherFactory.cacher.get(string) != null) {
				v.add((V) CacherFactory.cacher.get(string));
			}
		}
		return v;
	}

}

(5)在自定义的CacheManager中加入自定义的Cache

public class SMCacheManager extends AbstractCacheManager {

	@SuppressWarnings("unused")
	private static final Logger logger = LoggerFactory.getLogger(SMCacheManager.class);

	@SuppressWarnings("rawtypes")
	@Resource
	private Cache shiroCache;

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.apache.shiro.cache.AbstractCacheManager#createCache(java.lang.String)
	 */
	@SuppressWarnings("rawtypes")
	@Override
	protected Cache createCache(String s) throws CacheException {
		//我这里是用Spring注入的,所以就直接返回了
		return shiroCache;
	}
}

(6)启动时设置缓存方式

public void initCache() {
		switchRedis = "OFF";
		try {
			switchRedis = systemSettingBiz.getSysDetail("system.redis.switch");
			redisTemplate.opsForValue().get("");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			log.error("------------------------------redis缓存关闭,切换到ehCacher----------------------");
			switchRedis = "OFF";
		}
		if (switchRedis.equalsIgnoreCase("OFF")) {
			log.info("----------------------开启ehCacher------------------------------");
			CacherFactory.setAdpt(ehCacher);
		} else {
			log.info("----------------------开启redisCacher----------------------------");
			CacherFactory.setAdpt(redisCacher);
		}
	}

(7)修改Shiro配置文件

<bean id="cacheManager" class="com.cn.contiy.system.shiro.entity.SMCacheManager" />

至此,完成,代码写得比较渣,请大佬莫怪,仅仅提供一个想法
这种方式的有点就是Shiro不需要在乎你使用的是什么缓存,可以说将Shiro的缓存已经抽象出来了,可以这么说,就算,你的Shiro使用缓存的方式,使用数据库的方式,也只需要实现Cacher接口,在应用启动时设置开关切换,即可实现Shiro的缓存,而自定义缓存更多的为了将Session统一,对于分布式的系统,个人觉得还是非常重要的。

PS:处女文,请大佬多多指点,谢谢!(手下留情)

内容概要:本文档聚焦于“基于粒子群算法(PSO)的路径规划问题研究”,结合Matlab代码实现,系统阐述了PSO算法在路径规划中的应用原理与实践方法。文档不仅提供了详细的算法实现流程,还拓展介绍了智能优化算法、机器学习、信号处理、电力系统、无人机路径规划等多个前沿科研方向的技术服务内容,涵盖多种复杂优化问题的建模范例与仿真案例。特别强调在科研过程中“借力”的重要性,提倡借助成熟算法与仿真工具推动创新研究。文档附有多个网盘链接,便于读者获取完整的代码、模型及复现资料,支持对高水平论文(如博士/硕士论文、EI/SCI期刊)的算法复现与技术延伸。; 适合人群:具备一定Matlab编程基础,从事自动化、电气工程、控制科学、计算机、通信工程、机械电子等相关领域的研究生、科研人员及工程技术人员。; 使用场景及目标:①深入学习粒子群算法在路径规划中的建模与实现过程;②掌握多种智能优化算法(如GWO、PSO、DWA等)与机器学习模型在复杂工程问题中的集成应用;③复现高水平学术论文中的算法模型,提升科研创新能力与仿真实践水平。; 阅读建议:建议按照文档结构顺序系统阅读,优先关注与自身研究方向紧密相关的技术模块,结合提供的Matlab代码与Simulink仿真模型进行动手实践,充分利用网盘资源开展算法调试、模型优化与论文复现工作,以实现从理论到应用的有效转化。
内容概要:本文聚焦于光伏并网逆变器与虚拟同步发电机(VSG)在弱电网条件下的正负序阻抗建模与稳定性分析,基于Simulink平台构建详细的系统仿真模型。研究通过扫频法对两类并网系统的序阻抗特性进行辨识与验证,深入探讨其在弱电网环境中的交互作用与稳定裕度差异。重点剖析了光伏逆变器与VSG的控制结构对其阻抗特性的影响,对比两者在正负序阻抗建模中的动态响应特征,揭示其潜在的宽频带振荡风险。研究成果为新能源高比例接入背景下并网系统的稳定性评估、振荡机理分析及控制策略优化提供了理论依据与技术支撑,具有较强的工程应用价值。; 适合人群:具备电力电子、自动控制及电力系统分析基础知识,从事新能源并网、微电网控制、逆变器建模与稳定性研究的研究生、科研人员及电力系统相关领域的工程技术人员。; 使用场景及目标:①掌握光伏并网逆变器与虚拟同步发电机的正负序阻抗建模方法;②理解基于扫频法的阻抗特性辨识与稳定性判据(如奈奎斯特判据)的应用;③深入分析弱电网条件下并网系统的交互稳定性问题;④为相关科研项目、学位论文撰写或工程实践中的模型搭建与仿真验证提供参考与技术支持。; 阅读建议:建议结合文中提供的Simulink仿真模型与代码资源(可通过指定公众号及网盘链接获取),在学习理论的同时动手复现仿真过程,重点关注扫频激励信号的设计、阻抗数据的提取与处理、以及稳定性判据的图形化分析,从而深化对并网系统小信号稳定性的理解,并可进一步拓展至构网型变流器或多机并网等复杂场景的研究。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值