EhCache 是一個純Java的進程內緩存框架,具備快速、精幹等特色,是Hibernate中默認的CacheProvider,同時在項目開發中也被普遍使用到。接下來就以用戶緩存爲例,基於javaweb項目來搭建ehcache緩存系統。
java
主要涉及核心原理和實現要點:項目是基於spring框架來統一管理和配置bean的,因此在spring中配置緩存,定義EhCacheManagerFactoryBean,同時指向其ehcache配置文件ehcache.xml,ehcache.xml則有咱們本身根據項目狀況來定義一些緩存策略,如:cache中元素的生存時間、cache 中最多能夠存放的元素的數量和內存存儲與釋放策略等等。java代碼中則能夠定義一個統一的緩存管理類去持有net.sf.ehcache.CacheManager實例,來代理往數據庫中操做數據的行爲。關於CacheManager實例的獲取,則能夠經過實現ApplicationContextAware, DisposableBean接口,分別重寫其setApplicationContext()方法,注入ApplicationContext到靜態變量中和destroy()方法,在ApplicationContext關閉時清理靜態變量。這樣以靜態變量保存Spring ApplicationContext, 可在任何代碼任何地方任什麼時候候取出ApplicaitonContext,進而調用其getBean()方法來得到CacheManager實例。拿數據是先getByCache(),若緩存中存在數據則直接返回該數據,若緩存中不存在數據,再執行getByDb(),從數據庫中拿數據,同時將數據存進緩存中。web
一、首先從web.xml部署文件入口進行配置spring
<!-- 應用程序Spring上下文配置 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath*:applicationContext*.xml, </param-value> </context-param> <!-- 自定義監聽器 繼承自spring上下文加載監聽器 --> <listener> <listener-class>com.schoolnet.sys.listener.WebContextListener</listener-class> </listener>
繼承自spring上下文加載監聽器的WebContextListener類,能夠在web啓動時作一些處理數據庫
WebContextListener .java緩存
public class WebContextListener extends org.springframework.web.context.ContextLoaderListener { @Override public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { if (!printKeyLoadMessage()){ return null; } return super.initWebApplicationContext(servletContext); } private static boolean printKeyLoadMessage(){ StringBuilder sb = new StringBuilder(); sb.append("\r\n======================================================================\r\n"); sb.append("\r\n 歡迎使用 校園網 - EhCache緩存系統搭建\r\n"); sb.append("\r\n======================================================================\r\n"); System.out.println(sb.toString()); return true; } }
二、applicationContex.xml中配置ehcache緩存app
<!-- 加載配置屬性文件 --> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="fileEncoding" value="UTF-8" /> <property name="locations"> <list> <value>classpath:schoolnet.properties</value> </list> </property> </bean> <!-- 緩存配置 --> <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation" value="classpath:${ehcache.configFile}" /> </bean>
三、schoolnet.properties框架
ehcache.configFile=cache/ehcache.xml(源碼包下的cache文件夾中)
四、ehcache.xmlide
<?xml version="1.0" encoding="UTF-8"?> <ehcache updateCheck="false" name="defaultCache"> <diskStore path="../temp/jeesite/ehcache" /> <!-- 默認緩存配置. --> <defaultCache maxEntriesLocalHeap="100" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true" maxEntriesLocalDisk="100000" /> <!-- 系統緩存 --> <cache name="sysCache" maxEntriesLocalHeap="100" eternal="true" overflowToDisk="true"/> <!-- 用戶緩存 --> <cache name="userCache" maxEntriesLocalHeap="100" eternal="true" overflowToDisk="true"/> <!-- 系統活動會話緩存 --> <cache name="activeSessionsCache" maxEntriesLocalHeap="10000" overflowToDisk="true" eternal="true" timeToLiveSeconds="0" timeToIdleSeconds="0" diskPersistent="true" diskExpiryThreadIntervalSeconds="600"/> <!-- 簡單頁面緩存 <cache name="SimplePageCachingFilter" maxEntriesLocalHeap="100" eternal="false" overflowToDisk="true" timeToIdleSeconds="120" timeToLiveSeconds="120" memoryStoreEvictionPolicy="LFU"/> --> </ehcache>
一些配置參數的說明工具
maxElementsInMemory :cache 中最多能夠存放的元素的數量。若是放入cache中的元素超過這個數值,有兩種狀況:一、若overflowToDisk的屬性值爲true,會將cache中多出的元素放入磁盤文件中。二、若overflowToDisk的屬性值爲false,會根據memoryStoreEvictionPolicy的策略替換cache中原有的元素。
eternal :意思是是否永駐內存。若是值是true,cache中的元素將一直保存在內存中,不會由於時間超時而丟失,因此在這個值爲true的時候,timeToIdleSeconds和timeToLiveSeconds兩個屬性的值就不起做用了。
timeToIdleSeconds :就是訪問這個cache中元素的最大間隔時間。若是超過這個時間沒有訪問這個cache中的某個元素,那麼這個元素將被從cache中清除。
timeToLiveSeconds : 這是cache中元素的生存時間。意思是從cache中的某個元素從建立到消亡的時間,從建立開始計時,當超過這個時間,這個元素將被從cache中清除。
overflowToDisk :溢出是否寫入磁盤。系統會根據標籤<diskStore path="java.io.tmpdir"/> 中path的值查找對應的屬性值,若是系統的java.io.tmpdir的值是 D:/temp,寫入磁盤的文件就會放在這個文件夾下。文件的名稱是cache的名稱,後綴名的data。如:CACHE_FUNC.data。這個屬性在解釋maxElementsInMemory的時候也已經說過了。
diskExpiryThreadIntervalSeconds :磁盤緩存的清理線程運行間隔
memoryStoreEvictionPolicy :內存存儲與釋放策略。有三個值:
LRU -least recently used
LFU -least frequently used
FIFO-first in first out, the oldest element by creation time
diskPersistent : 是否持久化磁盤緩存。當這個屬性的值爲true時,系統在初始化的時候會在磁盤中查找文件名爲cache名稱,後綴名爲index的的文件,如CACHE_FUNC.index 。這個文件中存放了已經持久化在磁盤中的cache的index,找到後把cache加載到內存。要想把cache真正持久化到磁盤,寫程序時必須注意,在是用net.sf.ehcache.Cache的void put (Element element)方法後要使用void flush()方法。
ui
五、CacheUtils.java
/** * Cache工具類 */ public class CacheUtils { private static CacheManager cacheManager = ((CacheManager)SpringContext.getBean("cacheManager")); private static final String SYS_CACHE = "sysCache"; /** * 獲取SYS_CACHE緩存 * @param key * @return */ public static Object get(String key) { return get(SYS_CACHE, key); } /** * 寫入SYS_CACHE緩存 * @param key * @return */ public static void put(String key, Object value) { put(SYS_CACHE, key, value); } /** * 從SYS_CACHE緩存中移除 * @param key * @return */ public static void remove(String key) { remove(SYS_CACHE, key); } /** * 獲取緩存 * @param cacheName * @param key * @return */ public static Object get(String cacheName, String key) { Element element = getCache(cacheName).get(key); return element==null?null:element.getObjectValue(); } /** * 寫入緩存 * @param cacheName * @param key * @param value */ public static void put(String cacheName, String key, Object value) { Element element = new Element(key, value); getCache(cacheName).put(element); } /** * 從緩存中移除 * @param cacheName * @param key */ public static void remove(String cacheName, String key) { getCache(cacheName).remove(key); } /** * 得到一個Cache,沒有則建立一個。 * @param cacheName * @return */ private static Cache getCache(String cacheName){ Cache cache = cacheManager.getCache(cacheName); if (cache == null){ cacheManager.addCache(cacheName); cache = cacheManager.getCache(cacheName); cache.getCacheConfiguration().setEternal(true); } return cache; } public static CacheManager getCacheManager() { return cacheManager; } } 6、SpringContext.java,用類得到ApplicationContext實例 @Component public class SpringContext implements ApplicationContextAware,DisposableBean{ private static ApplicationContext applicationContext; /** * 取得存儲在靜態變量中的ApplicationContext. */ @Override public void setApplicationContext(ApplicationContext context) throws BeansException { try { applicationContext=context; } catch (Exception e) { e.printStackTrace(); } } /** * 從靜態變量applicationContext中取得Bean, 自動轉型爲所賦值對象的類型. */ public static <T> T getBean(String name){ return (T) applicationContext.getBean(name); } public static String[] getBeanNamesForType(Class<?> type){ return applicationContext.getBeanNamesForType(type); } /** * 實現DisposableBean接口, 在Context關閉時清理靜態變量. */ @Override public void destroy() throws Exception { applicationContext = null; } }
七、UserUtils.java
/** * 用戶工具類 */ public class UserUtils { private static UserDao userDao = SpringContextHolder.getBean(UserDao.class); private static Map<String, Object> cacheMap; /** * 根據ID獲取用戶 * @param id * @return 取不到返回null */ public static User getUser(String id){ User user = (User)CacheUtils.get("userCache", "id_" + id); if (user == null){ user = userDao.get(id); if (user == null){ return null; } CacheUtils.put("userCache", "id_" + user.getId(), user); CacheUtils.put("userCache", "ln" + user.getLoginName(), user); } return user; } /** * 根據登陸名獲取用戶 * @param loginName * @return 取不到返回null */ public static User getByLoginName(String loginName){ User user = (User)CacheUtils.get("userCache", "ln" + loginName); if (user == null){ user = userDao.getByLoginName(new User(null, loginName)); if (user == null){ return null; } CacheUtils.put("userCache", "id_" + user.getId(), user); CacheUtils.put("userCache", "ln" + user.getLoginName(), user); } return user; } /** * 清除用戶緩存 * @param user */ public static void clearCache(User user){ CacheUtils.remove("userCache", "id_" + user.getId()); CacheUtils.remove("userCache", "ln" + user.getLoginName()); CacheUtils.remove("userCache", "ln" + user.getOldLoginName()); } }