shiro安全框架扩展教程--如何扩展实现我们的缓存机制(第三方容器redis,memcached)

简介:             上一章我们讲解了如何扩展集中式的session管理方便我们集群的应用项目,无须再使用复制session的方式来完善用户体系;下面我主要分享如何扩展shiro里的缓存实...

            上一章我们讲解了如何扩展集中式的session管理方便我们集群的应用项目,无须再使用复制session的方式来完善用户体系;下面我主要分享如何扩展shiro里的缓存实现,

大家都知道有点规模的项目都必须会使用缓存这个好东西,所以一个好的框架基本都会包含一套多级缓存的机制,例如spring,hibernate等也会有自己一套,象第三方的oscache,ehcache等等;


不扯没营养的话了,还是说回shiro的缓存,shiro的缓存比较简单,我们可以看看shiro定义的cache接口源码


package org.apache.shiro.cache;

import java.util.Collection;
import java.util.Set;

// Referenced classes of package org.apache.shiro.cache:
//            CacheException

public interface Cache
{

    public abstract Object get(Object obj)
        throws CacheException;

    public abstract Object put(Object obj, Object obj1)
        throws CacheException;

    public abstract Object remove(Object obj)
        throws CacheException;

    public abstract void clear()
        throws CacheException;

    public abstract int size();

    public abstract Set keys();

    public abstract Collection values();
}

很明显看到跟我们普通的cache差不多,也是CRUD等等方法,然后看看有shiro写的有哪些实现类

一个是org.apache.shiro.cache.ehcache.EhCache

一个是org.apache.shiro.cache.MapCache

然后看着名字我们就大概知道一个是基于encache框架来作为实现类基础,一个是以本地map来装载数据到内存达到缓存的效果,这里类的源码可以自己看看,比较简单,shiro入门后的都能看懂,但是这些实现类都不适合我用,我想要的是用memcached或是redis作为数据的缓存容器


下面我就来分享下自己的实现流程



上面我们已经看过shiro的cache接口,下面我们就实现一个序列化的cache实现类


/**
 * 
 * 缓存实现类,实现序列 接口方便对象存储于第三方容器(Map存放键值对)
 * 
 * 
 */
@SuppressWarnings("serial")
public class SimpleMapCache implements Cache<Object, Object>, Serializable {

	private final Map<Object, Object> attributes;
	private final String name;

	public SimpleMapCache(String name, Map<Object, Object> backingMap) {
		if (name == null)
			throw new IllegalArgumentException("Cache name cannot be null.");
		if (backingMap == null) {
			throw new IllegalArgumentException("Backing map cannot be null.");
		} else {
			this.name = name;
			attributes = backingMap;
		}
	}

	public Object get(Object key) throws CacheException {
		return attributes.get(key);
	}

	public Object put(Object key, Object value) throws CacheException {
		return attributes.put(key, value);
	}

	public Object remove(Object key) throws CacheException {
		return attributes.remove(key);
	}

	public void clear() throws CacheException {
		attributes.clear();
	}

	public int size() {
		return attributes.size();
	}

	public Set<Object> keys() {
		Set<Object> keys = attributes.keySet();
		if (!keys.isEmpty())
			return Collections.unmodifiableSet(keys);
		else
			return Collections.emptySet();
	}

	public Collection<Object> values() {
		Collection<Object> values = attributes.values();
		if (!CollectionUtils.isEmpty(values))
			return Collections.unmodifiableCollection(values);
		else
			return Collections.emptySet();
	}

	public String toString() {
		return (new StringBuilder("SimpleMapCache '")).append(name).append("' (").append(attributes.size()).append(
				" entries)").toString();
	}

}


其实上面的cache实现我直接用mapcache实现类的源码然后增加实现序列化的接口,比较方便


然后我们把自己的资源搞到一个map里,然后new SimpleMapCache(Map)就生成一个缓存堆,最后添加到缓存管理器里面即可


下面我们看看如何实现缓存管理器


所以我们先实现一个自定义的缓存管理器接口方便我们操作每一个缓存堆


/**
 * 
 * 缓存管理器接口
 * 
 * @author shadow
 * 
 */
public interface SimpleCacheManager {

	/**
	 * 新增缓存堆到管理器
	 * 
	 * @param name
	 * @param cache
	 */
	public abstract void createCache(String name, Cache<Object, Object> cache) throws CacheException;

	/**
	 * 获取缓存堆
	 * 
	 * @param name
	 * @return
	 * @throws CacheException
	 */
	public abstract Cache<Object, Object> getCache(String name) throws CacheException;

	/**
	 * 移除缓存堆
	 * 
	 * @param name
	 * @throws CacheException
	 */
	public abstract void removeCache(String name) throws CacheException;

	/**
	 * 更新缓存堆
	 * 
	 * @param name
	 * @param cache
	 */
	public abstract void updateCahce(String name, Cache<Object, Object> cache) throws CacheException;

	/**
	 * 注销管理器
	 */
	public abstract void destroy() throws CacheException;
}

接口已经定义好,我们就写一个实现类完成我们的逻辑,并且这个逻辑是把缓存堆对象放到memcached里面


/**
 * 
 * 缓存管理器实现类
 * 
 * @author shadow
 * 
 */
public class SimpleCacheManagerImpl implements SimpleCacheManager {

	private MemcachedClient memcachedClient;

	public SimpleCacheManagerImpl(MemcachedClient memcachedClient) {
		if (memcachedClient == null) {
			throw new RuntimeException("必须存在memcached客户端实例");
		}
		this.memcachedClient = memcachedClient;
	}

	@Override
	public void createCache(String name, Cache<Object, Object> cache) throws CacheException {
		try {
			memcachedClient.set(name, 0, cache);
		} catch (Exception e) {
			throw new CacheException(e);
		}
	}

	@Override
	public Cache<Object, Object> getCache(String name) throws CacheException {
		try {
			return memcachedClient.get(name);
		} catch (Exception e) {
			throw new CacheException(e);
		}
	}

	@Override
	public void removeCache(String name) throws CacheException {
		try {
			memcachedClient.delete(name);
		} catch (Exception e) {
			throw new CacheException(e);
		}
	}

	@Override
	public void updateCahce(String name, Cache<Object, Object> cache) throws CacheException {
		try {
			memcachedClient.replace(name, 0, cache);
		} catch (Exception e) {
			throw new CacheException(e);
		}
	}

	@Override
	public void destroy() throws CacheException {
		try {
			memcachedClient.shutdown();
		} catch (Exception e) {
			throw new CacheException(e);
		}
	}

}


然后我们就开始把这自定义的管理器接入到shiro的缓存管理器


/**
 * 
 * 安全框架缓存管理器实现类
 * 
 * @author shadow
 * 
 */
public class ShiroCacheManager implements CacheManager, Destroyable {

	private SimpleCacheManager simpleCacheManager;

	@Override
	public Cache<Object, Object> getCache(String name) throws CacheException {
		return simpleCacheManager.getCache(name);
	}

	@Override
	public void destroy() throws Exception {
		simpleCacheManager.destroy();
	}

	public SimpleCacheManager getSimpleCacheManager() {
		return simpleCacheManager;
	}

	public void setSimpleCacheManager(SimpleCacheManager simpleCacheManager) {
		this.simpleCacheManager = simpleCacheManager;
	}

}


最后配置下这个shiro的管理器实现类注入到需要的地方即可


<!-- 安全管理器 -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="sessionManager" ref="sessionManager" />
		<property name="cacheManager" ref="shiroCacheManager" />
		<property name="realm" ref="simpleUserRealm" />
	</bean>

	<!-- 安全框架缓存管理器 -->
	<bean id="shiroCacheManager" class="com.silvery.security.shiro.cache.ShiroCacheManager">
		<property name="simpleCacheManager" ref="simpleCacheManager" />
	</bean>

	<!-- 扩展缓存管理器 -->
	<bean id="simpleCacheManager"
		class="com.silvery.security.shiro.cache.extend.impl.SimpleCacheManagerImpl">
		<constructor-arg ref="memcachedClient" />
	</bean>


配置好了之后,我们在需要地方把实例化的SimpeMapCache添加到我们的自己的管理器里面即可...


这个章节已经讲完了,谢谢大家的支持


欢迎拍砖...


目录
相关文章
|
5月前
|
缓存 Java 应用服务中间件
Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
本文详解Spring Boot十大核心配置优化技巧,涵盖Tomcat连接池、数据库连接池、Jackson时区、日志管理、缓存策略、异步线程池等关键配置,结合代码示例与通俗解释,助你轻松掌握高并发场景下的性能调优方法,适用于实际项目落地。
933 5
|
7月前
|
存储 缓存 Serverless
【Azure Container App】如何在Consumption类型的容器应用环境中缓存Docker镜像
在 Azure 容器应用的 Consumption 模式下,容器每次启动均需重新拉取镜像,导致冷启动延迟。本文分析该机制,并提出优化方案:使用 ACR 区域复制加速镜像拉取、优化镜像体积、设置最小副本数减少冷启动频率,或切换至 Dedicated 模式实现镜像缓存,以提升容器启动效率和应用响应速度。
221 0
|
9月前
|
缓存 NoSQL 算法
Redis数据库的键值过期和删除机制
我们需要注意的是,虽然Redis提供了这么多高级的缓存机制,但在使用过程中,必须理解应用的特性,选择合适的缓存策略,才能最大化Redis的性能。因此,在设计和实施应用程序时,理解应用的数据访问模式,以及这些模式如何与Redis的缓存机制相互作用,尤为重要。
301 24
|
7月前
|
存储 缓存 NoSQL
Spring Cache缓存框架
Spring Cache是Spring体系下的标准化缓存框架,支持多种缓存(如Redis、EhCache、Caffeine),可独立或组合使用。其优势包括平滑迁移、注解与编程两种使用方式,以及高度解耦和灵活管理。通过动态代理实现缓存操作,适用于不同业务场景。
617 0
|
缓存 NoSQL Java
什么是缓存?如何在 Spring Boot 中使用缓存框架
什么是缓存?如何在 Spring Boot 中使用缓存框架
924 0
|
11月前
|
缓存 NoSQL Java
Redis应用—8.相关的缓存框架
本文介绍了Ehcache和Guava Cache两个缓存框架及其使用方法,以及如何自定义缓存。主要内容包括:Ehcache缓存框架、Guava Cache缓存框架、自定义缓存。总结:Ehcache适合用作本地缓存或与Redis结合使用,Guava Cache则提供了更灵活的缓存管理和更高的并发性能。自定义缓存可以根据具体需求选择不同的数据结构和引用类型来实现特定的缓存策略。
739 16
Redis应用—8.相关的缓存框架
|
NoSQL Redis 数据库
Redis 功能扩展 Lua 脚本 对Redis扩展 eval redis.call redis.pcall
通过本文的介绍,我们详细讲解了 Lua 脚本在 Redis 中的作用、`eval` 命令的使用方法以及 `redis.call` 和 `redis.pcall` 的区别和用法。通过合理使用 Lua 脚本,可以实现复杂的业务逻辑,确保操作的原子性,并减少网络开销,从而提高系统的性能和可靠性。
795 13
|
存储 缓存 自然语言处理
SCOPE:面向大语言模型长序列生成的双阶段KV缓存优化框架
KV缓存是大语言模型(LLM)处理长文本的关键性能瓶颈,现有研究多聚焦于预填充阶段优化,忽视了解码阶段的重要性。本文提出SCOPE框架,通过分离预填充与解码阶段的KV缓存策略,实现高效管理。SCOPE保留预填充阶段的关键信息,并在解码阶段引入滑动窗口等策略,确保重要特征的有效选取。实验表明,SCOPE仅用35%原始内存即可达到接近完整缓存的性能水平,显著提升了长文本生成任务的效率和准确性。
731 3
SCOPE:面向大语言模型长序列生成的双阶段KV缓存优化框架
|
NoSQL API Redis
在C程序中实现类似Redis的SCAN机制的LevelDB大规模key分批扫描
通过上述步骤,可以在C程序中实现类似Redis的SCAN机制的LevelDB大规模key分批扫描。利用LevelDB的迭代器,可以高效地遍历和处理数据库中的大量键值对。该实现方法不仅简单易懂,还具有良好的性能和扩展性,希望能为您的开发工作提供实用的指导和帮助。
224 7
|
消息中间件 人工智能 Kubernetes
解密开源Serverless容器框架:事件驱动篇
Knative是一款基于Kubernetes的开源Serverless框架,提供了云原生、跨平台的Serverless编排标准。作为Serverless中必不可少的事件驱动能力,Knative Eventing提供了云原生的事件驱动能力。