Memcached是前台应用系统主要的分布式缓存工具。为了简化操作,引入了SSM(Simple-Spring-Memcached)工具。
SSM本身不提供任何缓存,是为了简化缓存操作而设计的。所以,在缓存的实现上使用了第三方的组件:spymemcached,xmemcached 和 aws-elasticache 。
SSM的源代码托管:https://github.com/ragnor/simple-spring-memcached
SSM的文档:https://code.google.com/p/simple-spring-memcached (非常遗憾,经常访问不了)
1、配置文件
1.1 依赖包
如果通过maven管理,引入非常简单。
<dependencies> <dependency> <groupId>com.google.code.simple-spring-memcached</groupId> <artifactId>xmemcached-provider</artifactId> <version>3.6.0</version> </dependency> </dependencies>
1.2 spring的配置文件
新增:
<!--把CacheBase注入到Advice中,默认使用自己jar包中的配置文件--> <import resource="classpath:simplesm-context.xml"/> <!--打开aop注解--> <aop:aspectj-autoproxy/> <!--定义缓存客户端--> <bean name="defaultMemcachedClient" class="com.google.code.ssm.CacheFactory"> <property name="cacheClientFactory"> <!--可配置不同的客户端,比如sypMemcached等--> <bean class="com.google.code.ssm.providers.xmemcached.MemcacheClientFactoryImpl"/> </property> <property name="addressProvider"> <!--缓存服务器集群地址,还可以使用JndiAddressProvider--> <bean class="com.google.code.ssm.config.DefaultAddressProvider"> <!--缓存集群地址--> <property name="address" value="${memcached.servers}"/> </bean> </property> <property name="configuration"> <bean class="com.google.code.ssm.providers.CacheConfiguration"> <property name="consistentHashing" value="true"/> <!--缓存操作超时时间--> <property name="operationTimeout" value="${memcached.timeout}"/> <!--3.3.0版本后,新增了keyName的前缀功能,可能是考虑到不同应用使用同一个集群,避免KEY覆盖的情况。useNameAsKeyPrefix keyPrefixSeparator--> </bean> </property> </bean> <!--加载properties文件-> <beans profile="zsc1"> <context:property-placeholder location="classpath:zsc1/*.properties,classpath:*.properties" file-encoding="utf-8" /> </beans> <beans profile="zsc2"> <context:property-placeholder location="classpath:zsc2/*.properties,classpath:*.properties" file-encoding="utf-8" /> </beans> <beans profile="pro"> <context:property-placeholder location="classpath:pro/*.properties,classpath:*.properties" file-encoding="utf-8" /> </beans>
1.3 memcached.properties文件
#集群 主节点,备节点 主节点,备节点 #memcached.servers=172.16.20.1:11211,172.16.20.2:12211 172.16.20.3:11211,172.16.10.4:12211 172.16.10.5:11212,172.16.10.6:12211 172.16.10.7:11212,172.16.20.8:12211 memcached.servers=172.16.50.66:11211 memcached.timeout=1000
2、注解
SSM本质上是采用了AOP的方式来实现缓存的调用和管理,其核心组件声明了一些Advice,当遇到相应的切入点时,会执行这些Advice来对memcached加以管理。
切入点是通过注解的方式来进行声明的,在项目开发时,通常在方法上加以相应的注解描述,来表示组件对该方法的拦截。
组件所提供的切入点主要包括以下几种:
ReadThroughSingleCache、ReadThroughMultiCache、ReadThroughAssignCache
当遇到查询方法声明这些切入点时,组件首先会从缓存中读取数据,取到数据则跳过查询方法,直接返回。取不到数据在执行查询方法,并将查询结果放入缓存,以便下一次获取。
InvalidateSingleCache、InvalidateMultiCache、InvalidateAssignCache
当遇到删除方法声明这些切入点时,组件会删除缓存中的对应实体。
UpdateSingleCache、UpdateMultiCache、UpdateAssignCache
当遇到更新方法声明这些切入点是,组件会更新缓存中对应的实体,以便下次从缓存中读取出的数据状态是最新的。
缓存的keyName,一般是由namespace 和 唯一性的值组合而成。
CacheKeyMethod、ParameterValueKeyProvider 生成缓存key。
以下是这些注解的详细使用说明:
@CacheName:指定缓存实例注解
@CacheKeyMethod:缓存key生成注解
--------------------------------- 读取 ---------------------------------
2.1 ReadThroughSingleCache
读取单个缓存
从缓存中读取value,如果缓存中没有,执行被注解的方法体,并将执行结果放倒缓存中。返回方法体的执行结果。
keyName的生成,通过 获取注解中的 namespace属性值以及ParameterValueKeyProvider 和 CacheKeyMethod注解的内容 获取。
ReadThroughSingleCache源码
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @CacheOperation({CacheOperation.Type.READ, CacheOperation.Type.SINGLE}) public @interface ReadThroughSingleCache { /** * A namespace that is added to the key as it is stored in the distributed cache. This allows differing object that * may have the same ID to coexist. This value must be assigned. * * @return the namespace for the objects cached in the given method. */ String namespace() default AnnotationConstants.DEFAULT_STRING; /** * The exp value is passed along to memcached exactly as given, and will be processed per the memcached protocol * specification: * * The actual value sent may either be Unix time (number of seconds since January 1, 1970, as a 32-bit value), or a * number of seconds starting from current time. In the latter case, this number of seconds may not exceed * 60*60*24*30 (number of seconds in 30 days); if the number sent by a client is larger than that, the server will * consider it to be real Unix time value rather than an offset from current time. * * (Also note: a value of 0 means the given value should never expire. The value is still susceptible to purging by * memcached for space and LRU (least recently used) considerations.) * * @return expiration of cached data */ int expiration() default 0; }
例子:
namespace:命名空间
expiration:缓存时间
/** * 获取银行列表接口查询结果,该结果获取后会被缓存。 * KEY:CacheConstant.NAMESPACE_BANK_LIST_INFO 和 BankListIn 对象中getCacheKey() 方法的返回值的组合。 */ @ReadThroughSingleCache(namespace = CacheConstant.NAMESPACE_BANK_LIST_INFO, expiration = CacheConstant.EXP_SECONDS_BANK_LIST_INFO) public UniResult<List<BankListOut>> getBankList(@ParameterValueKeyProvider BankListIn bankListIn) throws Throwable { // 序列化接口入参 String url = InterfaceConfig.getInterface("/tianyimall/banklist"); url = URLUtil.ObjectToURL(url, bankListIn); // 反序列化接口出参 return excuteGet(url, new TypeReference<UniResult<List<BankListOut>>>() {}); }
BankListIn
public class BankListIn implements Serializable{ private static final long serialVersionUID = 9168068757534717931L; /** * 类型 */ private String type; /** * 支付平台ID */ private String paymentplatformid; /** * type. * * @return the type * @since */ public String getType() { return type; } /** * type. * * @param type the type to set * @since */ public void setType(String type) { this.type = type; } /** * paymentplatformid. * * @return the paymentplatformid * @since */ public String getPaymentplatformid() { return paymentplatformid; } /** * paymentplatformid. * * @param paymentplatformid the paymentplatformid to set * @since */ public void setPaymentplatformid(String paymentplatformid) { this.paymentplatformid = paymentplatformid; } @CacheKeyMethod public String getCacheKey(){ return type+"_"+paymentplatformid; } }
2.2 ReadThroughMultiCache
@ReadThroughMultiCache(option = @ReadThroughMultiCacheOption(generateKeysFromResult = true)):读取多个缓存
@ReadThroughMultiCacheOption(generateKeysFromResult = true) 读取多个缓存操作generateKeysFromResult 通过结果生成key
例子:ReadThroughMultiCache
@ReadThroughMultiCache(namespace = CacheConstant.NAMESPACE_BASIC_INFO, expiration = CacheConstant.EXP_SECONDS_BASIC_INFO) public List<SPProductInfo> getProductBasicInfoByPids(@ParameterValueKeyProvider List<String> salesPids) throws Throwable { List<SPProductInfo> list = new ArrayList<>(); for (String salesPid : salesPids) { list.add(getProductBasicInfoByPid(salesPid)); } return list; }
2.3 ReadThroughAssignCache
这个注解在没有参数,也就是没有@ParameterValueKeyProvider 的时候,会指定key,比如下面的SomePhatKey
@ReadThroughAssignCache(assignedKey = "SomePhatKey", namespace = "Echo", expiration = 3000): 读取指定key缓存
例子:ReadThroughtAssignCache
@ReadThroughAssignCache(assignedKey = "userKey", namespace = "test", expiration = 3000) public List getAllUser(){ System.out.println("没有缓存命中"); List l = new ArrayList(3); l.add("1"); return l; }
--------------------------------- 失效 ---------------------------------
InvalidateSingleCache
@InvalidateSingleCache(namespace = SINGLE_NS):失效单个缓存
InvalidateMultiCache
@InvalidateMultiCache(namespace = "Delta") : 失效多个缓存
InvalidateAssignCache
@InvalidateAssignCache(assignedKey = "SomePhatKey", namespace = "Echo") : 指定key失效缓存
InvalidateAssignCache
@InvalidateAssignCache(assignedKey = "userKey", namespace = "test") // assignedKey 也是不可缺少的,参数和返回值 不是必须的 public User delete() throws Exception{ User user = new User(); return user; }
--------------------------------- 更新 ---------------------------------
UpdateSingleCache
@UpdateSingleCache(namespace = SINGLE_NS, expiration = 2): 更新单个缓存(namespace 命名空间, expiration 失效时间单位秒)
UpdateMultiCache
@UpdateMultiCache(namespace = "Bravo", expiration = 300): 更新多个缓存
UpdateAssignCache
@UpdateAssignCache(assignedKey = "SomePhatKey", namespace = "Echo", expiration = 3000): 指定key更新缓存
UpdateMultiCacheOption
--------------------------------- 参数 ---------------------------------
ParameterDataUpdateContent
@ParameterDataUpdateContent: 标记方法的参数作为更新内容。这个注解应结合Update*Cache注解使用
ParameterValueKeyProvider
@ParameterValueKeyProvider: 标记将方法的参数做为计算缓存key.如果方法被注解的对象标记CacheKeyMethod的方法将会用来生成缓存key否则调用toString()生成
@ParameterValueKeyProvider(order=0): 属性表示如果多个参数做为key时需提供参数顺序
与@ParameterValueKeyProvider类似的注解有:
{
@ReturnValueKeyProvider: 返回值对象中计算key
}
ReturnDataUpdateContent
spring xmemcached 注解介绍
http://greemranqq.iteye.com/blog/2169594
simple-spring-memcached那些事三
http://my.oschina.net/orgsky/blog/424727?fromerr=bme8sZfS