主要内容
shiro缓存机制
shiro中的缓存由CacheManager接口提供支持,shiro官方提供的shiro-ehcache库实现了该接口。也就是说,shiro的缓存机制依赖于ehcache库,因此,当项目中需要使用缓存的时候,需要另外导入shiro-ehcache库和ehcache核心库。
缓存的好处不用多说,它能够提高程序的执行效率,有效提供io的利用率。
shiro中可以使用缓存的地方有两个,分别是Realm缓存和Session缓存。默认情况下,缓存功能是关闭状态的。
Realm缓存
所有继承自CachingRealm
的Realm类都可以被缓存,得益于它的CacheManager
属性。一般,被缓存的信息都是验证和授权信息,从AuthenticatingRealm和AuthorizingRealm的源码可知,它们会先尝试到缓存中取出验证和授权信息,如果找到,则返回缓存中的信息,否则到保存这些信息的地方获取。
开启Realm缓存
以JdbcRealm为例子,在spring的applicationContext文件中开启缓存的方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<!--缓存管理器对象--> <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManagerConfigFile" value="classpath:shiro-cache.xml" /> </bean> <!--配置security manager 使用jdbcRealm查询数据库--> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="jdbcRealm"/> <property name="sessionManager" ref="sessionManager" /> </bean> <bean id="jdbcRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm"> <property name="dataSource" ref="dataSource"/> <!--配置缓存管理器--> <property name="cacheManager" ref="cacheManager" /> <!--开启缓存--> <property name="cachingEnabled" value="true" /> <!--配置验证缓存--> <property name="authenticationCachingEnabled" value="true" /> <property name="authenticationCacheName" value="authenticationCache" /> <!--配置授权缓存--> <property name="authorizationCachingEnabled" value="true" /> <property name="authorizationCacheName" value="authorizatonCache" /> <property name="authenticationQuery" value="select password from user where username = ?"/> </bean> |
缓存配置文件shiro-cache
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<cache name="authenticationCache" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="false" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" /> <cache name="authorizationCache" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="false" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" |
name属性和applicationContext中配置的authenticationCacheName和authorizationCacheName匹配。
缓存成功开启之后,用户第一次通过subject.login
方法登录之后,用户的验证信息和授权信息都会被保存起来,只要缓存未过期和未被清除,用户下次登录的时候提交的账号信息就会和缓存中的做比较,如果匹配就可以成功登录,即使数据库中的信息已经被更新过,所以,数据库信息更新之后最好手动清除缓存。
清除缓存的方法有两种:
第一种是直接调用CachingRealm的clearCacheXXX()方法,例如AuthenticatingRealm调用clearCachedAuthenticationInfo()清除验证缓存;AuthorizingRealm则调用clearCachedAuthorizationInfo()方法清除授权缓存。
第二种是调用subject.logout()方法,logout方法被执行的时候会同时清空账号信息缓存。subject.logout方法最终会调用CachingRealm的onLogout方法。下面是CachingRealm的onLogout()方法的源码:
Session缓存
Session缓存和Realm缓存使用的可以是同一个CacheManger对象,也可以使用不同的对象,为了方便,这里使用了相同的CacheManager。
开启Session缓存
和Realm一样,session缓存的配置也是非常简单的,不同的是,session中的缓存是通过SessionDao操作CacheManager实现的。从DefaultSessionManager类中可以查到下面的代码:
applicationContext配置文件:
1 2 3 4 5 6 7 8 9 |
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <property name="sessionDAO" ref="enterpriseCacheSessionDAO" /> </bean> <!--配置SessionDao缓存--> <bean id="enterpriseCacheSessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"> <property name="cacheManager" ref="cacheManager" /> <property name="activeSessionsCacheName" value="activeSessionCache" /> </bean> |
因为和上面的Realm使用的同一个CacheManager,这里不再重复配置。
缓存配置文件shiro-cache
1 2 3 4 5 6 7 8 |
<cache name="activeSessionCache" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="false" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" /> |
完整applicationContext配置文件
如果Realm和SessionDao使用的是同一个CacheManager对象,可以直接把这个对象注入到SecurityManager中,而不再需要单独配置Realm和SessionDao的注入。
完整配置文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--开启组件扫描 并设置扫描的基础包--> <context:component-scan base-package="cn.sharpcode"/> <!--设置模板解析器--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/"/> <property name="suffix" value=".jsp"/> </bean> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="loginUrl" value="/login"/> <property name="unauthorizedUrl" value="/unauthorized"/> <property name="securityManager" ref="securityManager"/> <property name="filterChainDefinitions"> <value> /login=anon /admin=authc </value> </property> </bean> <bean id="sessionListener" class="org.apache.shiro.session.SessionListenerAdapter"/> <!--配置security manager 使用jdbcRealm查询数据库--> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="jdbcRealm"/> <!--把cacheManager统一注入到SecurityManager中--> <property name="cacheManager" ref="cacheManager" /> <property name="sessionManager" ref="sessionManager"/> </bean> <!--缓存管理器对象--> <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManagerConfigFile" value="classpath:shiro-cache.xml"/> </bean> <bean id="jdbcRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm"> <property name="dataSource" ref="dataSource"/> <!--开启缓存--> <property name="cachingEnabled" value="true"/> <!--配置验证缓存--> <property name="authenticationCachingEnabled" value="true"/> <property name="authenticationCacheName" value="authenticationCache"/> <!--配置授权缓存--> <property name="authorizationCachingEnabled" value="true"/> <property name="authorizationCacheName" value="authorizationCache"/> <property name="authenticationQuery" value="select password from user where username = ?"/> </bean> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <property name="sessionDAO" ref="enterpriseCacheSessionDAO"/> </bean> <!--配置SessionDao缓存--> <bean id="enterpriseCacheSessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"> <property name="activeSessionsCacheName" value="activeSessionCache"/> </bean> <!--配置数据源--> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql:///shiro?useSSL=true"/> <property name="username" value="gino"/> <property name="password" value="123"/> </bean> </beans> |
可能遇到的问题
可能会遇到下面的异常:
Another unnamed CacheManager already exists in the same VM
异常原因
Ehcache 2.5版本之后不再允许多个相同名字的CacheManager存在于jvm中,但是默认情况下CacheManager并不以单例的形式创建。需要指出的是,这个CacheManager并不是shiro提供的CacheManager接口,而是ehcache库下的一个具体类。
解决办法
使用CacheManager类的静态方法create()
创建对象,create()方法会检查当前环境下是否已经存在CacheManager对象,如果存在则直接返回该对象,否则创建一个新的对象。
applicationContext文件相关配置:
1 2 3 4 5 6 7 8 9 10 |
<!--缓存管理器对象--> <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManagerConfigFile" value="classpath:shiro-cache.xml" /> <!-- 配置Cache Manager为单例 --> <property name="cacheManager" ref="coreCacheManager" /> </bean> <!-- 配置Cache Manager为单例 --> <bean id="coreCacheManager" class="net.sf.ehcache.CacheManager" factory-method="create" /> |
转载请注明:Pure nonsense » shiro使用缓存