刨根问底--技术--encache缓存应用

    中国高校大约2000多所学校,学校的基本信息一般不会改变。

    用户常见的操作会有查看学校的基本信息,以及分数的查询。假如每次都到数据库中取得学校的数据,是没有必要的,而且从数据库中取得数据的速度慢,怎么办呢?缓存应运而生。

    从网上大量的资料来看,大家普遍的都用encache框架来做缓存,没有什么好说的,研究研究她吧。

    encache的特性:

    1. 快速.
    2. 简单.
    3. 多种缓存策略
    4. 缓存数据有两级:内存和磁盘,因此无需担心容量问题
    5. 缓存数据会在虚拟机重启的过程中写入磁盘
    6. 可以通过RMI、可插入API等方式进行分布式缓存
    7. 具有缓存和缓存管理器的侦听接口
    8. 支持多缓存管理器实例,以及一个实例的多个缓存区域
    9. 提供Hibernate的缓存实现

具体代码架构图:

刨根问底--技术--encache缓存应用_第1张图片

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 [email protected] $
/**
 *  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,他是怎么设置进去的啊?并且读到里面的数据呢?


你可能感兴趣的:(刨根问底--技术--encache缓存应用)