• 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"/>

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

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

  • 相关阅读:
    mooc-IDEA 项目/文件之间跳转--002
    003--PowerDesigner创建索引与外键
    002--PowerDesigner显示注释comment
    001--PowerDesigner连接MySQL
    如果说需要注册数据中心,这样才能使用demo部署数据中心license证需要申请,使用云之间-工作流程......
    eas之如何获取当前用户
    eas之f7
    eas之打开窗体
    eas之怎么设置单据保存或者提交完不跳到下个新增页面
    eas之EntityViewInfo对象mainQuery中查询条件
  • 原文地址:https://www.cnblogs.com/zfding/p/8536480.html
Copyright © 2020-2023  润新知