Spring最近释出了3.1的REALEASE版本,到我写这篇日志的时候已经是3.1.2.REALEASE版本了,该版本直接内置了Ehcache的缓存注解,比起以前配置上是容易了许多,但是shiro官方却并没有为此3.1版本的注解缓存更新其最新的实现方式,为了能够用上最新版本的spring和shiro(1.2.1),特别针对缓存部分做了一些修改。
首先Spring 3.1及以后版本的cache功能位于spring-context包中,要使用spring3.1的缓存注解,只需要在spring的主配置xml文件中添加schema:
1
|
xmlns:cache="http://www.springframework.org/schema/cache"
|
记得在xsi:schemaLocation中增加:
1
|
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.1.xsd
|
注意:cache的schemaLocation暂时不支持不写版本号的xsd,也就是说,现在还必须写上spring-cache-3.1.xsd
然后写上
1
|
<cache:annotation-driven/>
|
就可以使用注解@Cacheable和@CacheEvict了
@Cacheable:要缓存的方法或者类,属性:value、key、condition,value是最主要的,对应ehcache.xml中声明的cache的name;key的主要作用我认为是给局部更新缓存使用的,并且支持SpEL;condition是触发条件,空表示全部增加,也支持SpEL。
@CacheEvict:要进行清空缓存的方法或者类,属性:value、key、condition、allEntries、beforeInvocation,前三者与@Cacheable类似,allEntries为true表示清空全部缓存,默认为false;beforeInvocation为true表示在方法执行以前清理缓存,默认为false
当然,如果想要详细的配置,就需要在xml中添加一些东西了:
1
2 3 4 5 6 7 8 9 10 11 12 13 |
<cache:annotation-driven cache-manager="cacheManager"/>
<bean id="cacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation" value="classpath:/config/ehcache.xml" /> </bean> <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"> <property name="cacheManager" ref="cacheManagerFactory" /> </bean> |
以上Spring 3.1的缓存注解就已经OK了,接下去就是Shiro的部分。
shiro目前还不支持直接使用上述Spring 3.1的配置,但是我们可以改造一下:
首先得写两个类进行注入:
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 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
/**
* */ package org.apache.shiro.cache.ehcacheSpring3_1; import java.io.IOException; import java.io.InputStream; import org.apache.shiro.ShiroException; import org.apache.shiro.cache.Cache; import org.apache.shiro.cache.CacheException; import org.apache.shiro.cache.CacheManager; import org.apache.shiro.config.ConfigurationException; import org.apache.shiro.io.ResourceUtils; import org.apache.shiro.util.Destroyable; import org.apache.shiro.util.Initializable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cache.ehcache.EhCacheCacheManager; /** * @author Yockii * */ public class EhCacheManager implements CacheManager, Initializable, Destroyable { private static final Logger log = LoggerFactory.getLogger(EhCacheManager.class); protected org.springframework.cache.ehcache.EhCacheCacheManager manager; private boolean cacheManagerImplicitlyCreated = false; private String cacheManagerConfigFile = "classpath:org/apache/shiro/cache/ehcache/ehcache.xml"; public EhCacheManager(){} public org.springframework.cache.ehcache.EhCacheCacheManager getCacheManager(){ return manager; } public void setCacheManager(org.springframework.cache.ehcache.EhCacheCacheManager manager){ this.manager = manager; } public String getCacheManagerConfigFile(){ return this.cacheManagerConfigFile; } public void setCacheManagerConfigFile(String classpathLocation){ this.cacheManagerConfigFile = classpathLocation; } protected InputStream getCacheManagerConfigFileInputStream(){ String configFile = getCacheManagerConfigFile(); try{ return ResourceUtils.getInputStreamForPath(configFile); } catch (IOException e) { throw new ConfigurationException("Unable to obtain input stream for cacheManagerConfigFile [" + configFile + "]", e); } } /* (non-Javadoc) * @see org.apache.shiro.util.Destroyable#destroy() */ @Override public void destroy() throws Exception { // TODO Auto-generated method stub } /* (non-Javadoc) * @see org.apache.shiro.util.Initializable#init() */ @Override public void init() throws ShiroException { // TODO Auto-generated method stub } /* (non-Javadoc) * @see org.apache.shiro.cache.CacheManager#getCache(java.lang.String) */ @Override public final <K, V> Cache<K, V> getCache(String name) throws CacheException { if(log.isTraceEnabled()){ log.trace("Acquiring EhCache instance named [" + name + "]"); } try{ org.springframework.cache.Cache cache = manager.getCache(name); if(cache == null){ if(log.isInfoEnabled()){ log.info("Cache with name '{}' does not yet exist. Creating now.", name); } this.manager.getCacheManager().addCache(name); cache = manager.getCache(name); if(log.isInfoEnabled()){ log.info("Added EhCache named [" + name + "]"); } } else { if(log.isInfoEnabled()){ log.info("Using existing EHCache named [" + cache.getName() + "]"); } } return new EhCache<K, V>(cache); } catch (Exception e) { throw new CacheException(e); } } private EhCacheCacheManager ensureCacheManager(){ try{ if(this.manager == null){ if(log.isDebugEnabled()){ log.debug("cacheManager property not set. Constructing CacheManager instance... "); } this.manager = new org.springframework.cache.ehcache.EhCacheCacheManager(); manager.setCacheManager(new net.sf.ehcache.CacheManager(getCacheManagerConfigFileInputStream())); if(log.isTraceEnabled()){ log.trace("instantiated Ehcache CacheManager instance WITH SPRING EhCacheCacheManager"); } cacheManagerImplicitlyCreated = true; if(log.isDebugEnabled()){ log.debug("implicit cacheManager created WITH SPRING EhCacheCacheManager successfully."); } } return this.manager; } catch (Exception e) { throw new CacheException(e); } } } |
这个是主要的缓存管理类,还有一个缓存类hack类Ehcache
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 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
/**
* */ package org.apache.shiro.cache.ehcacheSpring3_1; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import net.sf.ehcache.Ehcache; import org.apache.shiro.cache.Cache; import org.apache.shiro.cache.CacheException; import org.apache.shiro.util.CollectionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cache.Cache.ValueWrapper; /** * @author Yockii * */ public class EhCache<K, V> implements Cache<K, V> { private static final Logger log = LoggerFactory.getLogger(EhCache.class); private org.springframework.cache.Cache cache; public EhCache(org.springframework.cache.Cache cache) { if (cache == null) { throw new IllegalArgumentException("Cache argument cannot be null."); } this.cache = cache; } @Override public V get(K key) throws CacheException { try { if (log.isTraceEnabled()) { log.trace("Getting object from cache [" + cache.getName() + "] for key [" + key + "]"); } if (key == null) { return null; } else { ValueWrapper vw = cache.get(key); if (vw == null) { if (log.isTraceEnabled()) { log.trace("ValueWrapper for [" + key + "] is null."); } return null; } else { return (V) vw.get(); } } } catch (Throwable t) { throw new CacheException(t); } } @Override public V put(K key, V value) throws CacheException { if (log.isTraceEnabled()) { log.trace("Putting object in cache [" + cache.getName() + "] for key [" + key + "]"); } try { V previous = get(key); cache.put(key, value); return previous; } catch (Throwable t) { throw new CacheException(t); } } @Override public V remove(K key) throws CacheException { if (log.isTraceEnabled()) { log.trace("Removing object from cache [" + cache.getName() + "] for key [" + key + "]"); } try { V previous = get(key); cache.evict(key); return previous; } catch (Throwable t) { throw new CacheException(t); } } @Override public void clear() throws CacheException { if (log.isTraceEnabled()) { log.trace("Clearing all objects from cache [" + cache.getName() + "]"); } try { cache.clear(); } catch (Throwable t) { throw new CacheException(t); } } @Override public int size() { try { return ((Ehcache) cache.getNativeCache()).getSize(); } catch (Throwable t) { throw new CacheException(t); } } @Override public Set<K> keys() { try { Ehcache ehcache = (Ehcache) cache.getNativeCache(); @SuppressWarnings("unchecked") List<K> keys = ehcache.getKeys(); if (!CollectionUtils.isEmpty(keys)) { return Collections.unmodifiableSet(new LinkedHashSet<K>(keys)); } else { return Collections.emptySet(); } } catch (Throwable t) { throw new CacheException(t); } } @Override public Collection<V> values() { try { Ehcache ehcache = (Ehcache) cache.getNativeCache(); @SuppressWarnings("unchecked") List<K> keys = ehcache.getKeys(); if (!CollectionUtils.isEmpty(keys)) { List<V> values = new ArrayList<V>(keys.size()); for (K key : keys) { V value = get(key); if (value != null) { values.add(value); } } return Collections.unmodifiableList(values); } else { return Collections.emptyList(); } } catch (Throwable t) { throw new CacheException(t); } } public long getMemoryUsage() { try { return ((Ehcache) cache.getNativeCache()).calculateInMemorySize(); } catch (Throwable t) { return -1; } } public long getMemoryStoreSize() { try { return ((Ehcache) cache.getNativeCache()).getMemoryStoreSize(); } catch (Throwable t) { throw new CacheException(t); } } public long getDiskStoreSize() { try { return ((Ehcache) cache.getNativeCache()).getDiskStoreSize(); } catch (Throwable t) { throw new CacheException(t); } } public String toString() { return "EhCache [" + cache.getName() + "]"; } } |
然后再在spring配置文件中加入shiro的spring配置信息,可以参考之前的博客或者官方的spring联合部分
注意这里shiro部分缓存cacheManage使用上面Spring的cacheManager,而注入到shiro缓存中的类要使用上面的org.apache.shiro.cache.ehcacheSpring3_1.EhCacheManager
改造这样就应该可以了,暂时未验证!