在前面的几篇博文中,我们记录了Memcached整合spring的一些方法,现在我们就基于这些方法实现一个Memcached整合Spring的完整示例,好了不多说了,我们直接上代码吧。
package com.zp.framework.cache.memcached; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.springframework.cache.Cache; import org.springframework.cache.transaction.AbstractTransactionSupportingCacheManager; import com.whalin.MemCached.MemCachedClient; /** * Spring Cache整合Memcached实现 * @author xiaoyao */ public class MemcachedCacheManager extends AbstractTransactionSupportingCacheManager { private ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<String, Cache>(); private Map<String, Integer> expireMap = new HashMap<String, Integer>(); //缓存的时间 private MemCachedClient memcachedClient; //memcached的客户端 public MemcachedCacheManager() { } @Override protected Collection<? extends Cache> loadCaches() { Collection<Cache> values = cacheMap.values(); return values; } @Override public Cache getCache(String name) { Cache cache = cacheMap.get(name); if (cache == null) { Integer expire = expireMap.get(name); if (expire == null) { expire = 0; expireMap.put(name, expire); } cache = new MemcachedCache(name, expire.intValue(), memcachedClient); cacheMap.put(name, cache); } return cache; } public void setMemcachedClient(MemCachedClient memcachedClient) { this.memcachedClient = memcachedClient; } public void setConfigMap(Map<String, Integer> configMap) { this.expireMap = configMap; } }
package com.zp.framework.cache.memcached; import org.springframework.cache.Cache; import org.springframework.cache.support.SimpleValueWrapper; import com.whalin.MemCached.MemCachedClient; /** * MemcachedCache的实现,主要实现spring的cache接口 * @author xiaoyao * */ public class MemcachedCache implements Cache { private final String name; private final MemCache memCache; public MemcachedCache(String name, int expire, MemCachedClient memcachedClient) { this.name = name; this.memCache = new MemCache(name, expire, memcachedClient); } @Override public void clear() { memCache.clear(); } @Override public void evict(Object key) { memCache.delete(key.toString()); } @Override public ValueWrapper get(Object key) { ValueWrapper wrapper = null; Object value = memCache.get(key.toString()); if (value != null) { wrapper = new SimpleValueWrapper(value); } return wrapper; } @Override public String getName() { return this.name; } @Override public MemCache getNativeCache() { return this.memCache; } @Override public void put(Object key, Object value) { memCache.put(key.toString(), value); } @Override @SuppressWarnings("unchecked") public <T> T get(Object key, Class<T> type) { Object cacheValue = this.memCache.get(key.toString()); Object value = (cacheValue != null ? cacheValue : null); if (type != null && !type.isInstance(value)) { throw new IllegalStateException("Cached value is not of required type [" + type.getName() + "]: " + value); } return (T) value; } }
package com.zp.framework.cache.memcached; import java.util.HashSet; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.whalin.MemCached.MemCachedClient; /** * Memcached的封装类 * @author xiaoyao * */ public class MemCache { private static Logger log = LoggerFactory.getLogger(MemCache.class); private Set<String> keySet = new HashSet<String>(); private final String name; private final int expire; private final MemCachedClient memcachedClient; public MemCache(String name, int expire, MemCachedClient memcachedClient) { this.name = name; this.expire = expire; this.memcachedClient = memcachedClient; } public Object get(String key) { Object value = null; try { key = this.getKey(key); value = memcachedClient.get(key); } catch (Exception e) { log.warn("获取 Memcached 缓存超时", e); } return value; } public void put(String key, Object value) { if (value == null) return; try { key = this.getKey(key); memcachedClient.set(key, value, expire); keySet.add(key); }catch (Exception e) { log.warn("更新 Memcached 缓存错误", e); } } public void clear() { for (String key : keySet) { try { memcachedClient.delete(this.getKey(key)); }catch (Exception e) { log.warn("删除 Memcached 缓存错误", e); } } } public void delete(String key) { try { key = this.getKey(key); memcachedClient.delete(key); } catch (Exception e) { log.warn("删除 Memcached 缓存被中断", e); } } private String getKey(String key) { return name + "_" + key; } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:cache="http://www.springframework.org/schema/cache" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.2.xsd"> <!-- 扫描项目包的根路径 --> <context:component-scan base-package="com.zp" /> <context:component-scan base-package="com.zp.utils.dao.base.impl"/> <!-- =================================== 配置Memcached =============================== --> <!-- 开启缓存 --> <cache:annotation-driven cache-manager="cacheManager" proxy-target-class="true" /> <!-- 导入外部properties --> <context:property-placeholder location="classpath:memcached.properties"/> <bean id="memcachedPool" class="com.danga.MemCached.SockIOPool" factory-method="getInstance" init-method="initialize" destroy-method="shutDown"> <constructor-arg> <value>neeaMemcachedPool</value> </constructor-arg> <property name="servers"> <list> <value>${memcache.server}</value> </list> </property> <property name="initConn"> <value>${memcache.initConn}</value> </property> <property name="minConn"> <value>${memcache.minConn}</value> </property> <property name="maxConn"> <value>${memcache.maxConn}</value> </property> <property name="maintSleep"> <value>${memcache.maintSleep}</value> </property> <property name="nagle"> <value>${memcache.nagle}</value> </property> <property name="socketTO"> <value>${memcache.socketTO}</value> </property> </bean> <!-- 配置MemcachedClient --> <bean id="memcachedClient" class="com.whalin.MemCached.MemCachedClient"> <constructor-arg> <value>neeaMemcachedPool</value> </constructor-arg> </bean> <!-- 配置缓存管理 --> <bean id="cacheManager" class="com.zp.framework.cache.memcached.MemcachedCacheManager"> <property name="memcachedClient" ref="memcachedClient"/> <!-- 配置缓存时间 --> <property name="configMap"> <map> <!-- key缓存对象名称 value缓存过期时间 --> <entry key="systemCache" value="3600"/> </map> </property> </bean> <!-- 导入调度任务 --> <!-- <import resource="spring-quartz.xml" /> --> </beans>
#Memcached基本配置 memcache.server=192.168.254.120:12000 memcache.initConn=20 memcache.minConn=10 memcache.maxConn=50 memcache.maintSleep=3000 memcache.nagle=false memcache.socketTO=3000
6、web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>Smartlink</display-name> <!-- 配置spring监听器 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 配置初始化监听 --> <listener> <listener-class>com.zp.utils.listener.WebServerStartListener</listener-class> </listener> <!-- 加载配置文件路径 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:spring-*.xml</param-value> </context-param> <!-- springmvc配置 --> <servlet> <servlet-name>smartlink</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>smartlink</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- 配置OpenSessionInView --> <filter> <filter-name>hibernateFilter</filter-name> <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class> <!-- singleSession默认为true,若设为false则等于没用OpenSessionInView --> <init-param> <param-name>singleSession</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>hibernateFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 字符编码过滤器 --> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <error-page> <error-code>404</error-code> <location>/static/html/page_404/404.html</location> </error-page> </web-app>
7、pom.xml
<dependency> <groupId>com.whalin</groupId> <artifactId>Memcached-Java-Client</artifactId> <version>3.0.2</version> </dependency>
package com.zp.utils.service; import java.io.Serializable; /** * 带有缓存的service * @author xiaoyao * * @param <T> */ public interface CacheBaseService<T> extends SinglePKBaseService<T>{ T get(Serializable id); void save(T[] entity) ; void save(T entity) ; Serializable saveObj(T entity); void update(T entity) ; void delete(T entity) ; public int delete(Serializable id) ; public void delete(Serializable... id) ; }
package com.zp.utils.service.impl; import java.io.Serializable; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import com.zp.utils.service.CacheBaseService; public abstract class CacheBaseServiceImpl<T> extends SinglePKBaseServiceImpl<T> implements CacheBaseService<T>{ @Override @CachePut(value="systemCache") public T get(Serializable id){ return super.get(id); } @Override @CacheEvict(value="systemCache", allEntries = true, beforeInvocation = true) public void save(T[] entity) { super.save(entity); } @Override @CacheEvict(value="systemCache", allEntries = true, beforeInvocation = true) public void save(T entity){ super.save(entity); } @Override @CacheEvict(value="systemCache", allEntries = true, beforeInvocation = true) public Serializable saveObj(T entity){ return super.saveObj(entity); } @Override @CacheEvict(value="systemCache", allEntries = true, beforeInvocation = true) public void update(T entity){ super.update(entity); } @Override @CacheEvict(value="systemCache", allEntries = true, beforeInvocation = true) public void delete(T entity){ super.delete(entity); } @Override @CacheEvict(value="systemCache", beforeInvocation = true) public int delete(Serializable id){ return super.delete(id); } @Override @CacheEvict(value="systemCache", allEntries = true, beforeInvocation = true) public void delete(Serializable... id){ super.delete(id); } }
package com.zp.system.store.service; import java.util.List; import com.zp.system.store.entity.StoreAdvertment; import com.zp.utils.service.CacheBaseService; /** * 商家广告service * @author xiaoyao * */ public interface StoreAdvertmentService extends CacheBaseService<StoreAdvertment> { /** * 缓存key的前缀 */ String STORE_AD = "store_ad_"; /** * 获取广告图 * @param storeId * @param type * @param limit * @return */ List<StoreAdvertment> getStoreAdvertments(Long storeId, Integer type, int limit); }
package com.zp.system.store.service.impl; import java.util.List; import javax.annotation.Resource; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import com.cdsmartlink.system.store.dao.StoreAdvertmentDao; import com.cdsmartlink.system.store.entity.StoreAdvertment; import com.cdsmartlink.system.store.service.StoreAdvertmentService; import com.cdsmartlink.utils.dao.QueryMode; import com.cdsmartlink.utils.dao.QueryParse; import com.cdsmartlink.utils.dao.base.BaseDao; import com.cdsmartlink.utils.service.impl.CacheBaseServiceImpl; @Service public class StoreAdvertmentServiceImpl extends CacheBaseServiceImpl<StoreAdvertment> implements StoreAdvertmentService { @Resource private StoreAdvertmentDao storeAdvertmentDao; @Override protected BaseDao<StoreAdvertment> getDao() { return storeAdvertmentDao; } @Override protected void setQueryParse(QueryParse<StoreAdvertment> qp, QueryMode queryMode) { } @Override @Cacheable(value=SYSTEM_CACHE, key="'store_ad_'+ #storeId")//store_ad_为key的自定义字符串前缀,这个前缀可以根据具体业务设定,以免和其他缓存数据冲突,注意,这个字符串前缀要用单引号''括起来,否则会报错 public List<StoreAdvertment> getStoreAdvertments(Long storeId, Integer type, int limit) { return storeAdvertmentDao.getStoreAdvertments(storeId, type, limit); } }