中国高校大约2000多所学校,学校的基本信息一般不会改变。
用户常见的操作会有查看学校的基本信息,以及分数的查询。假如每次都到数据库中取得学校的数据,是没有必要的,而且从数据库中取得数据的速度慢,怎么办呢?缓存应运而生。
从网上大量的资料来看,大家普遍的都用encache框架来做缓存,没有什么好说的,研究研究她吧。
encache的特性:
1. 快速.
2. 简单.
3. 多种缓存策略
4. 缓存数据有两级:内存和磁盘,因此无需担心容量问题
5. 缓存数据会在虚拟机重启的过程中写入磁盘
6. 可以通过RMI、可插入API等方式进行分布式缓存
7. 具有缓存和缓存管理器的侦听接口
8. 支持多缓存管理器实例,以及一个实例的多个缓存区域
9. 提供Hibernate的缓存实现
具体代码架构图:
0、首先加入ehcache-core-1.7.2.jar
1、Cache.java
package com.xing.core.cache;
import java.util.List;
/**
* Implementors define a caching algorithm. All implementors
* <b>must</b> be threadsafe.
*/
public interface Cache {
/**
* Get an item from the cache, nontransactionally
* @param key
* @return the cached object or <tt>null</tt>
* @throws CacheException
*/
public Object get(Object key) throws CacheException;
/**
* Add an item to the cache, nontransactionally, with
* failfast semantics
* @param key
* @param value
* @throws CacheException
*/
public void put(Object key, Object value) throws CacheException;
/**
* Add an item to the cache
* @param key
* @param value
* @throws CacheException
*/
public void update(Object key, Object value) throws CacheException;
@SuppressWarnings("rawtypes")
public List keys() throws CacheException ;
/**
* Remove an item from the cache
*/
public void remove(Object key) throws CacheException;
/**
* Clear the cache
*/
public void clear() throws CacheException;
/**
* Clean up
*/
public void destroy() throws CacheException;
}
2CacheException.java
package com.xing.core.cache;
/**
* Something went wrong in the cache
*/
public class CacheException extends RuntimeException {
private static final long serialVersionUID = -3044257085401548929L;
public CacheException(String s) {
super(s);
}
public CacheException(String s, Throwable e) {
super(s, e);
}
public CacheException(Throwable e) {
super(e);
}
}
3 CacheManager.java
package com.xing.core.cache;
import java.io.Serializable;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* 缓存助手
*/
public class CacheManager {
private final static Log log = LogFactory.getLog(CacheManager.class);
private static CacheProvider provider;
public static void init(String prv_name){
try{
CacheManager.provider = (CacheProvider)Class.forName(prv_name).newInstance();
CacheManager.provider.start();
}catch(Exception e){
log.fatal("Unabled to initialize cache provider:" + prv_name + ", using ehcache default.", e);
CacheManager.provider = new EhCacheProvider();
}
}
private final static Cache _getCache(String cache_name) {
if(provider == null){
provider = new EhCacheProvider();
provider.start();
}
return provider.buildCache(cache_name);
}
/**
* 获取缓存中的数据
* @param name 缓存名
* @param key
* @return
*/
public final static Object get(String name, Serializable key){
if(name!=null && key != null)
return _getCache(name).get(key);
return null;
}
/**
* 获取缓存中的数据
* @param <T>
* @param resultClass
* @param name
* @param key
* @return
*/
@SuppressWarnings("unchecked")
public final static <T> T get(Class<T> resultClass, String name, Serializable key){
if(name!=null && key != null)
return (T)_getCache(name).get(key);
return null;
}
/**
* 写入缓存
* @param name
* @param key
* @param value
*/
public final static void set(String name, Serializable key, Serializable value){
if(name!=null && key != null && value!=null)
_getCache(name).put(key, value);
}
/**
* 清除缓冲中的某个数据
* @param name
* @param key
*/
public final static void evict(String name, Serializable key){
if(name!=null && key != null)
_getCache(name).remove(key);
}
}
4 CacheProvider.java
package com.xing.core.cache;
/**
* Support for pluggable caches.
*/
public interface CacheProvider {
/**
* Configure the cache
*
* @param regionName the name of the cache region
* @param properties configuration settings
* @throws CacheException
*/
public Cache buildCache(String regionName) throws CacheException;
/**
* Callback to perform any necessary initialization of the underlying cache implementation
* during SessionFactory construction.
*
* @param properties current configuration settings.
*/
public void start() throws CacheException;
/**
* Callback to perform any necessary cleanup of the underlying cache implementation
* during SessionFactory.close().
*/
public void stop();
}
5 EhCache.java
//$Id: EhCache.java 10716 2006-11-03 19:05:11Z max.andersen@jboss.com $
/**
* Copyright 2003-2006 Greg Luck, Jboss Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.xing.core.cache;
import java.util.List;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
/**
* EHCache
*/
public class EhCache implements Cache {
private net.sf.ehcache.Cache cache;
/**
* Creates a new Hibernate pluggable cache based on a cache name.
* <p/>
*
* @param cache The underlying EhCache instance to use.
*/
public EhCache(net.sf.ehcache.Cache cache) {
this.cache = cache;
}
@SuppressWarnings("rawtypes")
public List keys() throws CacheException {
return this.cache.getKeys();
}
/**
* Gets a value of an element which matches the given key.
*
* @param key the key of the element to return.
* @return The value placed into the cache with an earlier put, or null if not found or expired
* @throws CacheException
*/
public Object get(Object key) throws CacheException {
try {
if ( key == null )
return null;
else {
Element element = cache.get( key );
if ( element != null )
return element.getObjectValue();
}
return null;
}
catch (net.sf.ehcache.CacheException e) {
throw new CacheException( e );
}
}
/**
* Puts an object into the cache.
*
* @param key a key
* @param value a value
* @throws CacheException if the {@link CacheManager}
* is shutdown or another {@link Exception} occurs.
*/
public void update(Object key, Object value) throws CacheException {
put( key, value );
}
/**
* Puts an object into the cache.
*
* @param key a key
* @param value a value
* @throws CacheException if the {@link CacheManager}
* is shutdown or another {@link Exception} occurs.
*/
public void put(Object key, Object value) throws CacheException {
try {
Element element = new Element( key, value );
cache.put( element );
}
catch (IllegalArgumentException e) {
throw new CacheException( e );
}
catch (IllegalStateException e) {
throw new CacheException( e );
}
catch (net.sf.ehcache.CacheException e) {
throw new CacheException( e );
}
}
/**
* Removes the element which matches the key.
* <p/>
* If no element matches, nothing is removed and no Exception is thrown.
*
* @param key the key of the element to remove
* @throws CacheException
*/
public void remove(Object key) throws CacheException {
try {
cache.remove( key );
}
catch (IllegalStateException e) {
throw new CacheException( e );
}
catch (net.sf.ehcache.CacheException e) {
throw new CacheException( e );
}
}
/**
* Remove all elements in the cache, but leave the cache
* in a useable state.
*
* @throws CacheException
*/
public void clear() throws CacheException {
try {
cache.removeAll();
}
catch (IllegalStateException e) {
throw new CacheException( e );
}
catch (net.sf.ehcache.CacheException e) {
throw new CacheException( e );
}
}
/**
* Remove the cache and make it unuseable.
*
* @throws CacheException
*/
public void destroy() throws CacheException {
try {
cache.getCacheManager().removeCache( cache.getName() );
}
catch (IllegalStateException e) {
throw new CacheException( e );
}
catch (net.sf.ehcache.CacheException e) {
throw new CacheException( e );
}
}
}
6 EhCacheProvider.java
//$Id: EhCacheProvider.java 9964 2006-05-30 15:40:54Z epbernard $
/**
* Copyright 2003-2006 Greg Luck, Jboss Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.xing.core.cache;
import java.util.Hashtable;
import net.sf.ehcache.CacheManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Cache Provider plugin
*
* Taken from EhCache 1.3 distribution
*/
public class EhCacheProvider implements CacheProvider {
private static final Log log = LogFactory.getLog(EhCacheProvider.class);
private CacheManager manager;
private Hashtable<String, EhCache> _cacheManager ;
/**
* Builds a Cache.
* <p>
* Even though this method provides properties, they are not used.
* Properties for EHCache are specified in the ehcache.xml file.
* Configuration will be read from ehcache.xml for a cache declaration
* where the name attribute matches the name parameter in this builder.
*
* @param name the name of the cache. Must match a cache configured in ehcache.xml
* @param properties not used
* @return a newly built cache will be built and initialised
* @throws CacheException inter alia, if a cache of the same name already exists
*/
public EhCache buildCache(String name) throws CacheException {
EhCache ehcache = _cacheManager.get(name);
if(ehcache != null)
return ehcache ;
try {
net.sf.ehcache.Cache cache = manager.getCache(name);
if (cache == null) {
log.warn("Could not find configuration [" + name + "]; using defaults.");
manager.addCache(name);
cache = manager.getCache(name);
log.debug("started EHCache region: " + name);
}
synchronized(_cacheManager){
ehcache = new EhCache(cache);
_cacheManager.put(name, ehcache);
return ehcache ;
}
}
catch (net.sf.ehcache.CacheException e) {
throw new CacheException(e);
}
}
/**
* Callback to perform any necessary initialization of the underlying cache implementation
* during SessionFactory construction.
*
* @param properties current configuration settings.
*/
public void start() throws CacheException {
if (manager != null) {
log.warn("Attempt to restart an already started EhCacheProvider. Use sessionFactory.close() " +
" between repeated calls to buildSessionFactory. Using previously created EhCacheProvider." +
" If this behaviour is required, consider using net.sf.ehcache.hibernate.SingletonEhCacheProvider.");
return;
}
manager = new CacheManager();
_cacheManager = new Hashtable<String, EhCache>();
}
/**
* Callback to perform any necessary cleanup of the underlying cache implementation
* during SessionFactory.close().
*/
public void stop() {
if (manager != null) {
manager.shutdown();
manager = null;
}
}
}
7 ICacheHelper.java
package com.xing.core.cache;
import java.io.Serializable;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* 自动缓存数据重加载
* @author Winter Lau
*/
public class ICacheHelper {
private static final Log log = LogFactory.getLog(ICacheHelper.class);
final static CacheUpdater g_ThreadPool = new CacheUpdater();
static class CacheUpdater extends ThreadPoolExecutor {
private List<String> runningThreadNames = new Vector<String>();
public CacheUpdater() {
super(0, 20, 5, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(20), new ThreadPoolExecutor.DiscardOldestPolicy());
}
public void execute(Thread command) {
if(runningThreadNames.contains(command.getName())){
log.warn(command.getName() + " ===================> Running.");
return ;
}
log.info(command.getName() + " ===================> Started.");
super.execute(command);
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
Thread thread = (Thread)r;
runningThreadNames.remove(thread.getName());
log.info(thread.getName() + " ===================> Finished.");
}
}
private final static String CACHE_GLOBAL = "icache-global";
/**
* 获取缓存数据
* @param region
* @param key
* @param invoker
* @param args
* @return
*/
public static Object get(final String region, final Serializable key,
final ICacheInvoker invoker, final Object... args) {
//1. 从正常缓存中获取数据
Object data = CacheManager.get(region, key);
if(data == null) {
final String global_key = key + "@" + region;
//2. 从全局二级缓存中获取数据
data = CacheManager.get(CACHE_GLOBAL, global_key);
//2.1 取不到为第一次运行
if(data == null){
if(invoker != null) {
data = invoker.callback(args);
if(data != null){
CacheManager.set(region, key, (Serializable)data);
CacheManager.set(CACHE_GLOBAL, global_key, (Serializable)data);
}
}
}
//2.2 如果取到了则执行自动更新数据策略
else if(invoker != null) {
String thread_name = "CacheUpdater-" + region + "-" + key;
//g_ThreadPool.execute(
new Thread(thread_name){
public void run(){
Object result = invoker.callback(args);
if(result != null){
CacheManager.set(region, key, (Serializable)result);
CacheManager.set(CACHE_GLOBAL, global_key, (Serializable)result);
}
}
}.start();
//);
}
}
return data;
}
}
8 ICacheInvoker.java
/**
*
*/
package com.xing.core.cache;
/**
* 回调接口
* @author Winter Lau
*/
public interface ICacheInvoker {
public Object callback(Object...args) ;
}
9 测试类TestEnCache.java
package com.xing.core.cache;
public class TestEnCache {
/**
* @param args
*/
public static void main(String[] args) {
String cacheName="cacheA";
String key="邯郸学院";
String value="很好啊";
//set(cacheName, key, value);
String gValue = (String)CacheManager.get(cacheName, key);//A
if(gValue!=null){
System.out.println("获取缓存成功:"+gValue);
}else{
System.out.println("获取缓存为空,设置缓存");
CacheManager.set(cacheName, key, value);
System.out.println("设置缓存之后获取缓存:"+(String)CacheManager.get(cacheName, key));
}
}
}
开始我很疑惑,我没有设置缓存文件ehcache.xml,他是怎么设置进去的啊?并且读到里面的数据呢?