Shiro緩存使用Redis、Ehcache、自帶的MpCache實現的三種方式實例

第一種:使用Redis作緩存,將數據存儲到redis數據庫中java

第一步:在項目裏面引入redis,配置文件以下:web

配置文件:spring_shiro_redis.xmlredis

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xmlns:p="http://www.springframework.org/schema/p"
 5        xmlns:c="http://www.springframework.org/schema/c"
 6        xmlns:cache="http://www.springframework.org/schema/cache"
 7        xsi:schemaLocation="http://www.springframework.org/schema/beans
 8        http://www.springframework.org/schema/beans/spring-beans.xsd
 9        http://www.springframework.org/schema/cache
10        http://www.springframework.org/schema/cache/spring-cache.xsd">
11       <description>spring-redis-cache配置文件</description> 
12 <!-- ###############################-Redis-########################################### -->
13     <!-- 配置redis和spring 的整合 -->
14     <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
15         <property name="maxTotal" value="${redis.maxTotal}" />
16         <property name="maxIdle" value="${redis.maxIdle}" />
17         <property name="maxWaitMillis" value="${redis.maxWaitMills}" />
18         <!-- <property name="testOnBorrow" value="${redis.pool.testOnBorrow}" /> -->
19     </bean>
20     <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
21         <property name="hostName" value="${redis.masterHost}" />
22         <property name="port" value="${redis.masterPort}" />
23         <property name="timeout" value="${redis.timeout}" />
24         <property name="password" value="${redis.masterPassword}" />
25         <property name="poolConfig" ref="jedisPoolConfig" />
26     </bean>
27     <bean id="template" class="org.springframework.data.redis.core.RedisTemplate">
28         <property name="connectionFactory" ref="jedisConnectionFactory" />
29         <!-- 開啓事務 -->
30         <property name="enableTransactionSupport" value="true" />
31         <!-- 序列化策略 推薦使用StringRedisSerializer -->
32         <!--  <property name="keySerializer">
33             <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
34         </property> -->
35         <!-- <property name="valueSerializer">
36             <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
37         </property> -->
38         <!--<property name="hashKeySerializer">
39             <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
40         </property>
41         <property name="hashValueSerializer">
42             <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
43         </property> -->
44         <property name="keySerializer">
45             <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"></bean>
46         </property>
47         <property name="valueSerializer">
48             <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
49         </property>
50         <property name="hashKeySerializer">
51             <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
52         </property>
53         <property name="hashValueSerializer">
54             <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
55         </property>
56     </bean>
57     <!--spring cache-->
58     <bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager"
59           c:redisOperations-ref="template">
60         <!-- 默認緩存10分鐘 -->
61         <property name="defaultExpiration" value="600"/>
62         <property name="usePrefix" value="true"/>
63         <!-- cacheName 緩存超時配置,半小時,一小時,一天 -->
64         <property name="expires">
65             <map key-type="java.lang.String" value-type="java.lang.Long">
66                 <entry key="halfHour" value="1800"/>
67                 <entry key="hour" value="3600"/>
68                 <entry key="oneDay" value="86400"/>
69                 <!-- shiro cache keys 對緩存的配置 -->
70                 <entry key="authorizationCache" value="1800"/>
71                 <entry key="authenticationCache" value="1800"/>
72                 <entry key="activeSessionCache" value="1800"/>
73             </map>
74         </property>
75     </bean>
76     <!-- cache註解,和spring-ehcache.xml中的只能使用一個 -->
77     <cache:annotation-driven cache-manager="cacheManager" proxy-target-class="true"/>
78 </beans>    

redis的配置文件redis.properties:spring

#Reids config
#最大可以保持活動的對象數
redis.maxIdle=10
redis.maxTotal=100
#當池內沒有返回對象時最大等待時間
redis.maxWaitMills=1000
#超時時間
redis.timeout=1000
#當調用borrow Object方法時,是否進行有效性檢查
redis.pool.testOnBorrow=true
#redis-master
redis.masterHost=192.168.206.128
redis.masterPort=6379
redis.masterPassword=1234

下面是spring-shiro.xml數據庫

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd"
    default-lazy-init="true">
    <description>Spring-shiro配置文件</description>
     <!--配置安全管理器-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <!--設置自定義Realm-->
        <property name="realm" ref="myRealm"/>
        <!--將緩存管理器,交給安全管理器-->
        <property name="cacheManager" ref="shiroSpringCacheManager"/>
        <!-- 記住密碼管理 -->
        <property name="rememberMeManager" ref="rememberMeManager"/>
        <property name="sessionManager" ref="sessionManager"/>
    </bean>
    <!-- 自定義realm -->
    <bean id = "myRealm" class="com.dzf.shiro.MyRealm">
        <property name="cacheManager" ref="shiroSpringCacheManager"/>
        <property name="credentialsMatcher" ref="myCredentialsMatcher"/>
        <!-- 打開緩存 -->
        <property name="cachingEnabled" value="true"/>
        <!-- 打開身份認證緩存 -->
        <property name="authenticationCachingEnabled" value="true"/>
        <!-- 打開受權緩存 -->
        <property name="authorizationCachingEnabled" value="true"/>
        <!-- 緩存AuthenticationInfo信息的緩存名稱 --> 
        <property name="authenticationCacheName" value="authenticationCache"/>
        <!-- 緩存AuthorizationInfo信息的緩存名稱 -->
        <property name="authorizationCacheName" value="authorizationCache"/>
    </bean>
    <!-- 配置自定義緩存管理器,中引入redis緩存管理器 -->
    <bean id = "shiroSpringCacheManager" class="com.dzf.shiro.ShiroSpringCacheManager"> <property name="cacheManager" ref="cacheManager"/> </bean>
     <!-- 密碼錯誤5次鎖定半小時 -->
    <bean id="myCredentialsMatcher" class="com.dzf.shiro.MyCredentialsMatcher">
        <property name="cacheManager" ref="shiroSpringCacheManager"/>
        <property name="limitCacheName" value="halfHour"/>
        <property name="passwordHash" ref="passwordHash"/>
    </bean>
    <bean id = "passwordHash"  class="com.dzf.shiro.PasswordHash">
        <!-- 使用MD5 -->
        <property name="hashAlgorithm" value="md5" />
        <!-- 加密5次 -->
        <property name="hashIterations" value="2"/>
    </bean>
     <!-- 記住密碼Cookie -->
    <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">  
            <!-- cookie的名字 -->
        <constructor-arg value="rememberMe"/>
        <property name="httpOnly" value="true"/>
        <!-- 7天,-->
        <property name="maxAge" value="604800"/>
    </bean>
    <!-- sesisonCookie 設置  -->
    <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">  
            <!-- cookie的名字 -->
        <constructor-arg value="sessionIdCookie"/>
        <property name="httpOnly" value="true"/>
        <!-- 30分鐘  單位是秒-->
        <property name="maxAge" value="1800"/>
    </bean>   
    <!-- rememberMe管理器,cipherKey生成見{@code Base64Test.java} -->
    <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
        <property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('5aaC5qKm5oqA5pyvAAAAAA==')}"/>
        <property name="cookie" ref="rememberMeCookie"/>  
    </bean>
     <!-- 會話管理器 -->
    <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
        <!-- 設置全局會話超時時間 半小時  單位是毫秒-->
        <property name="globalSessionTimeout" value="1800000"/>
        <!-- url上帶sessionId 默認爲true -->
        <property name="sessionIdUrlRewritingEnabled" value="false"/>
        <property name="sessionIdCookie" ref="sessionIdCookie"/>
        <property name="sessionDAO" ref="sessionDAO"/>
    </bean>
    
    <!-- 會話DAO 用於會話的CRUD -->
    <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
        <!-- Session緩存名字,配置30分鐘過時 -->
        <property name="activeSessionsCacheName" value="activeSessionCache"/>
        <property name="cacheManager" ref="shiroSpringCacheManager"/>
    </bean>
    <!-- Shiro Filter -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- 安全管理器 -->
        <property name="securityManager" ref="securityManager"/>
        <!-- 默認的登錄訪問url -->
        <property name="loginUrl" value="/login.jsp"/>
        <!-- 登錄成功後跳轉的url -->
        <!-- <property name="successUrl" value="/index.jsp"/> -->
        <!-- 沒有權限跳轉的url -->
        <property name="unauthorizedUrl" value="/unauth.jsp"/>
        <property name="filterChainDefinitions">
            <value>
                <!-- 
                    anon  不須要認證
                    authc 須要認證
                    user  驗證經過或RememberMe登陸的均可以
                -->
                /commons/** = anon
                /static/** = anon
                /user/login = anon
                /user/toLogin= anon
                /user/register = anon
                /register.jsp = anon
                /** = authc
            </value>
        </property>
    </bean>
    
    <!-- 靜態注入,至關於調用SecurityUtils.setSecurityManager(securityManager) -->
    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/>
        <property name="arguments" ref="securityManager"/>
    </bean>
    <!-- 保證明現了Shiro內部lifecycle函數的bean執行 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
</beans>    

第二步:定義本身的CacheManagerapache

 1 package com.dzf.shiro;
 2 
 3 import org.apache.shiro.cache.Cache;
 4 import org.apache.shiro.cache.CacheManager;
 5 import org.apache.shiro.util.Destroyable;
 6 /**
 7  * <p> 自定義cacheManage 擴張shiro裏面的緩存 使用reids做緩存 </p> 
 8  * <description>
 9  *  引入本身定義的CacheManager 
10  *  關於CacheManager的配置文件在spring-redis-cache.xml中
11  * </description>
12  * @author xxxx
13  * @date 2018年2月3日
14  * @time 14:01:53
15  */
16 
17 public class ShiroSpringCacheManager implements CacheManager ,Destroyable{
18     
19     private org.springframework.cache.CacheManager cacheManager;
20      
21     public org.springframework.cache.CacheManager getCacheManager() {
22         return cacheManager;
23     }
24 
25     public void setCacheManager(org.springframework.cache.CacheManager cacheManager) {
26         this.cacheManager = cacheManager;
27     }
28 
29     @Override
30     public void destroy() throws Exception {
31         cacheManager = null;
32     }
33 
34     @Override
35     public <K, V> Cache<K, V> getCache(String name)  {
36         if (name == null ){
37             return null;
38         }
39         return new ShiroSpringCache<K,V>(name,getCacheManager());
40     }
41 
42 
43 }

定義本身實現的Cache,實現了Shiro包裏的Cache緩存

 1 package com.dzf.shiro;
 2 
 3 import org.apache.shiro.cache.CacheException;
 4 import org.slf4j.Logger;
 5 import org.slf4j.LoggerFactory;
 6 import org.springframework.cache.Cache;
 7 import org.springframework.cache.Cache.ValueWrapper;
 8 import org.springframework.cache.CacheManager;
 9 
10 import java.util.Collection;
11 import java.util.Set;
12 
13 /**
14  * <p> 自定義緩存 將數據存入到redis中 </p>
15  * @author xxx
16  * @date 2018年2月1日
17  * @time 22:32:11
18  * @param <K>
19  * @param <V>
20  */
21 @SuppressWarnings("unchecked")
22 public class ShiroSpringCache<K,V> implements org.apache.shiro.cache.Cache<K, V>{
23     private static final Logger log = LoggerFactory.getLogger(ShiroSpringCache.class);
24     private CacheManager cacheManager;
25     private Cache cache;
26 //    private RedisCache cache2;
27     public ShiroSpringCache(String name, CacheManager cacheManager) {
28         if(name==null || cacheManager==null){
29             throw new IllegalArgumentException("cacheManager or CacheName cannot be null.");
30         }
31         this.cacheManager = cacheManager;
32         //這裏首先是從父類中獲取這個cache,若是沒有會建立一個redisCache,初始化這個redisCache的時候
33         //會設置它的過時時間若是沒有配置過這個緩存的,那麼默認的緩存時間是爲0的,若是配置了,就會把配置的時間賦予給這個RedisCache
34         //若是從緩存的過時時間爲0,就表示這個RedisCache不存在了,這個redisCache實現了spring中的cache
35         this.cache= cacheManager.getCache(name);
36     }
37     @Override
38     public V get(K key) throws CacheException {
39         log.info("從緩存中獲取key爲{}的緩存信息",key);
40         if(key == null){
41             return null;
42         }
43         ValueWrapper valueWrapper = cache.get(key);
44         if(valueWrapper==null){
46             return null;
47         }
48         return (V) valueWrapper.get();
49     }
50 
51     @Override
52     public V put(K key, V value) throws CacheException {
53         log.info("建立新的緩存,信息爲:{}={}",key,value);
54         cache.put(key, value);
55         return get(key);
56     }
57 
58     @Override
59     public V remove(K key) throws CacheException {
60         log.info("幹掉key爲{}的緩存",key);
61         V v = get(key);
62         cache.evict(key);//幹掉這個名字爲key的緩存
63         return v;
64     }
65 
66     @Override
67     public void clear() throws CacheException {
68         log.info("清空全部的緩存");
69         cache.clear();
70     }
71 
72     @Override
73     public int size() {
74         return cacheManager.getCacheNames().size();
75     }
76 
77     /**
78      * 獲取緩存中所的key值
79      */
80     @Override
81     public Set<K> keys() {
82         return (Set<K>) cacheManager.getCacheNames();
83     }
84 
85     /**
86      * 獲取緩存中全部的values值
87      */
88     @Override
89     public Collection<V> values() {
90         return (Collection<V>) cache.get(cacheManager.getCacheNames()).get();
91     }
92 
93     @Override
94     public String toString() {
95         return "ShiroSpringCache [cache=" + cache + "]";
96     }
97 }

我來稍微解釋下這個自定義ShiroSpringCache類中的CacheManager,這個是CacheManager其實就是RedisCacheManager,咱們經過getter和setter注入過,RedisCacheManager是CacheManager的實現類.本身跟着源碼看下去,一看就能夠看的懂。安全

到此爲止,使用redis作緩存,和spring的集成就完成了。注意:須要使用的緩存只須要在spring_shiro_redis.xml中配置就好了,放入緩存中的對象須要實現序列號接口cookie

第二種:使用Ehcache作緩存,能夠將數據存儲到磁盤中,也能夠存到內存中session

一樣須要配置文件:ehcache.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <ehcache updateCheck="false" dynamicConfig="false">
 3     <diskStore path="java.io.tmpdir"/>
 4     <!--受權信息緩存-->
 5     <cache name="authorizationCache"
 6            maxEntriesLocalHeap="2000"
 7            eternal="false"
 8            timeToIdleSeconds="1800"
 9            timeToLiveSeconds="1800"
10            overflowToDisk="false"
11            statistics="true">
12     </cache>
13 <!--身份信息緩存-->
14     <cache name="authenticationCache"
15            maxEntriesLocalHeap="2000"
16            eternal="false"
17            timeToIdleSeconds="1800"
18            timeToLiveSeconds="1800"
19            overflowToDisk="false"
20            statistics="true">
21     </cache>
22 <!--session緩存-->
23     <cache name="activeSessionCache"
24            maxEntriesLocalHeap="2000"
25            eternal="false"
26            timeToIdleSeconds="1800"
27            timeToLiveSeconds="1800"
28            overflowToDisk="false"
29            statistics="true">
30     </cache>
31 
32     <!-- 緩存半小時 -->
33     <cache name="halfHour"
34            maxElementsInMemory="10000"
35            maxElementsOnDisk="100000"
36            eternal="false"
37            timeToIdleSeconds="1800"
38            timeToLiveSeconds="1800"
39            overflowToDisk="false"
40            diskPersistent="false" />
41 
42     <!-- 緩存一小時 -->
43     <cache name="hour"
44            maxElementsInMemory="10000"
45            maxElementsOnDisk="100000"
46            eternal="false"
47            timeToIdleSeconds="3600"
48            timeToLiveSeconds="3600"
49            overflowToDisk="false"
50            diskPersistent="false" />
51 
52     <!-- 緩存一天 -->
53     <cache name="oneDay"
54            maxElementsInMemory="10000"
55            maxElementsOnDisk="100000"
56            eternal="false"
57            timeToIdleSeconds="86400"
58            timeToLiveSeconds="86400"
59            overflowToDisk="false"
60            diskPersistent="false" />
61 
62     <!--
63         name:緩存名稱。
64         maxElementsInMemory:緩存最大個數。
65         eternal:對象是否永久有效,一但設置了,timeout將不起做用。
66         timeToIdleSeconds:設置對象在失效前的容許閒置時間(單位:秒)。僅當eternal=false對象不是永久有效時使用,可選屬性,默認值是0,也就是可閒置時間無窮大。
67         timeToLiveSeconds:設置對象在失效前容許存活時間(單位:秒)。最大時間介於建立時間和失效時間之間。僅當eternal=false對象不是永久有效時使用,默認是0.,也就是對象存活時間無窮大。
68         overflowToDisk:當內存中對象數量達到maxElementsInMemory時,Ehcache將會對象寫到磁盤中。
69         diskSpoolBufferSizeMB:這個參數設置DiskStore(磁盤緩存)的緩存區大小。默認是30MB。每一個Cache都應該有本身的一個緩衝區。
70         maxElementsOnDisk:硬盤最大緩存個數。
71         diskPersistent:是否緩存虛擬機重啓期數據 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
72         diskExpiryThreadIntervalSeconds:磁盤失效線程運行時間間隔,默認是120秒。
73         memoryStoreEvictionPolicy:當達到maxElementsInMemory限制時,Ehcache將會根據指定的策略去清理內存。默認策略是LRU(最近最少使用)。你能夠設置爲FIFO(先進先出)或是LFU(較少使用)。
74         clearOnFlush:內存數量最大時是否清除。
75     -->
76     <defaultCache name="defaultCache"
77                   maxElementsInMemory="10000"
78                   eternal="false"
79                   timeToIdleSeconds="600"
80                   timeToLiveSeconds="600"
81                   overflowToDisk="false"
82                   maxElementsOnDisk="100000"
83                   diskPersistent="false"
84                   diskExpiryThreadIntervalSeconds="120"
85                   memoryStoreEvictionPolicy="LRU"/>
86 
87 </ehcache>

spring和ehcache集成的配置文件:spring_ehcache.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xmlns:cache="http://www.springframework.org/schema/cache"
 5        xsi:schemaLocation="http://www.springframework.org/schema/beans
 6        http://www.springframework.org/schema/beans/spring-beans.xsd
 7        http://www.springframework.org/schema/cache
 8        http://www.springframework.org/schema/cache/spring-cache.xsd">
 9     <!-- Spring提供的基於的Ehcache實現的緩存管理器 -->
10     <!-- 若是有多個ehcacheManager要在bean加上p:shared="true" -->
11     <bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" >
12         <property name="configLocation" value="classpath:ehcache.xml"/>
13     </bean>
14     <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
15         <property name="cacheManager" ref="ehcacheManager"/>
16         <property name="transactionAware" value="true"/>
17     </bean>
18     <!-- cache註解,和spring-redis.xml中的只能使用一個 -->
19     <cache:annotation-driven cache-manager="cacheManager" proxy-target-class="true"/>
20 </beans>

從redis切到ehcache,除了引入上面這兩個配置文件,其餘的基本沒有要動的,固然須要在spring.xml中,將spring-ehcache.xml引進去就像這樣:

1 <!--redis 和 ehcache 任選其一 -->
2     <import resource="spring-ehcache.xml"/>
3     <!--<import resource="spring-redis-cache.xml"/>-->
4     <import resource="spring-shiro.xml"/>

我想熟悉spring的小夥伴,這都看的懂吧,

這樣咱們就實現了從redis切到ehcache,須要格外注意的是,命名的規範性,各緩存的名字,各bean的id保持一致,切換才方便。

第三種:使用MemoryConstrainedCacheManager這個緩存管理器,將數據緩存到內存中去

解釋:Shiro已經爲咱們編寫了一套緩存的實現,那就是MpCache,是使用Map實現的,有興趣的能夠去看源碼

怎麼使用這個shiro已經爲咱們實現好的緩存,是很是容易的。

在上面的spring-shiro.xml中,我標紅的這一句:

1 <bean id = "shiroSpringCacheManager" class="com.dzf.shiro.ShiroSpringCacheManager">
2         <property name="cacheManager" ref="cacheManager"/>

只須要把這個改成下面這句:

1 <!-- 配置shiro自帶的緩存管理器 -->
2     <bean id = "shiroSpringCacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager"/>

就行了,對的,你沒有看錯,就是這麼的簡單。

好了,至此,三種實現都說完了,本身就本身的需求看,須要使用哪一種級別的緩存吧。

相關文章
相關標籤/搜索