• Shiro缓存使用Redis、Ehcache、自带的MpCache实现的三种方式实例


    第一种:使用Redis做缓存,将数据存储到redis数据库中

    第一步:在项目里面引入redis,配置文件如下:

    配置文件:spring_shiro_redis.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: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:

    #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>    

    第二步:定义自己的CacheManager

     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中配置就行了,放入缓存中的对象需要实现序列号接口

    第二种:使用Ehcache做缓存,可以将数据存储到磁盘中,也可以存到内存中

    同样需要配置文件: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"/>

    就好了,对的,你没有看错,就是这么的简单。

    好了,至此,三种实现都说完了,自己就自己的需求看,需要使用哪种级别的缓存吧。

  • 相关阅读:
    84. Largest Rectangle in Histogram (Solution 2)
    84. Largest Rectangle in Histogram (Solution 1)
    73. Set Matrix Zeroes
    【JavaScript】Symbol 静态方法
    【JavaScript】Date
    【JavaScript】Math
    725. Split Linked List in Parts把链表分成长度不超过1的若干部分
    791. Custom Sort String字符串保持字母一样,位置可以变
    508. Most Frequent Subtree Sum 最频繁的子树和
    762. Prime Number of Set Bits in Binary Representation二进制中有质数个1的数量
  • 原文地址:https://www.cnblogs.com/zfding/p/8536480.html
Copyright © 2020-2023  润新知