memcached是一种分布式缓存工具,有效提升了按主键检索数据的性能问题。
Simple-Spring-Memcached 是memcached与spring 框架整合的一种缓存框架,本质是采用aop的方式实现缓存的调用和管理。其核心组件声明了一些Advice,当遇到相应的切入点时,会执行这些Advice来对memcached 加以管理。
Simple-Spring-Memcached 本身不提供cache机制,需借助第三方组件,比如:spymemcached,xmemcached,aws-elasticache.
首先在pom中添加simple-spring-memcached的依赖
<dependency>
<groupId>com.google.code.simple-spring-memcached</groupId>
<artifactId>spring-cache</artifactId>
<version>3.6.0</version>
</dependency>
<dependency>
<groupId>com.google.code.simple-spring-memcached</groupId>
<artifactId>xmemcached-provider</artifactId>
<version>3.6.0</version>
</dependency>
然后在spring的配置文件中添加以下
<import resource="simplesm-context.xml" />
<aop:aspectj-autoproxy />
<cache:annotation-driven />
/*simplesm-context.xml封装在simple-spring-memcached-*.jar文件当中,主要用来加载组件核心的Advice,供程序调度使用。
而由于simple-spring-memcached主要是基于AOP的代理,所以加入<aop:aspectj-autoproxy />让代理机制起到作用。*/
<bean name="cacheManager" class="com.google.code.ssm.spring.SSMCacheManager">
<property name="caches">
<set>
<bean class="com.google.code.ssm.spring.SSMCache">
<constructor-arg name="cache" index="0" ref="defaultMemcachedClient" />
<constructor-arg name="expiration" index="1" value="300" />
<constructor-arg name="allowClear" index="2" value="false" />
</bean>
</set>
</property>
</bean>
<!--定义memcached客户端-->
<bean name="defaultMemcachedClient" class="com.google.code.ssm.CacheFactory">
<!-- xmemcached配置方法 -->
<property name="cacheClientFactory">
<bean name="cacheClientFactory" class="com.google.code.ssm.providers.xmemcached.MemcacheClientFactoryImpl" />
</property>
<!-- 定义了缓存节点的IP地址和端口号 -->
<property name="addressProvider">
<bean class="com.google.code.ssm.config.DefaultAddressProvider">
<property name="address" value="${memcached.address}" />
</bean>
</property>
<!-- 定义了缓存节点的查找方法 -->
<property name="configuration">
<bean class="com.google.code.ssm.providers.CacheConfiguration">
<property name="consistentHashing" value="true" />
</bean>
</property>
</bean>
simplesm-context.xml 采用默认的配置,如下:
<?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:context="http://www.springframework.org/schema/context"
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">
<!-- mode: ${mode} --> <!--<aop:aspectj-autoproxy /> -->
<context:component-scan base-package="com.google.code.ssm" />
<bean id="cacheBase" class="com.google.code.ssm.aop.CacheBase" />
<bean id="readThroughSingleCache" class="com.google.code.ssm.aop.ReadThroughSingleCacheAdvice">
<property name="cacheBase" ref="cacheBase" />
</bean>
<bean id="readThroughMultiCache" class="com.google.code.ssm.aop.ReadThroughMultiCacheAdvice">
<property name="cacheBase" ref="cacheBase" />
</bean>
<bean id="readThroughAssignCache" class="com.google.code.ssm.aop.ReadThroughAssignCacheAdvice">
<property name="cacheBase" ref="cacheBase" />
</bean>
<bean id="updateSingleCache" class="com.google.code.ssm.aop.UpdateSingleCacheAdvice">
<property name="cacheBase" ref="cacheBase" />
</bean>
<bean id="updateMultiCache" class="com.google.code.ssm.aop.UpdateMultiCacheAdvice">
<property name="cacheBase" ref="cacheBase" />
</bean>
<bean id="updateAssignCache" class="com.google.code.ssm.aop.UpdateAssignCacheAdvice">
<property name="cacheBase" ref="cacheBase" />
</bean>
<bean id="invalidateSingleCache" class="com.google.code.ssm.aop.InvalidateSingleCacheAdvice">
<property name="cacheBase" ref="cacheBase" />
</bean>
<bean id="invalidateMultiCache" class="com.google.code.ssm.aop.InvalidateMultiCacheAdvice">
<property name="cacheBase" ref="cacheBase" />
</bean>
<bean id="invalidateAssignCache" class="com.google.code.ssm.aop.InvalidateAssignCacheAdvice">
<property name="cacheBase" ref="cacheBase" />
</bean>
<bean id="incrementCounterInCache" class="com.google.code.ssm.aop.counter.IncrementCounterInCacheAdvice">
<property name="cacheBase" ref="cacheBase" />
</bean>
<bean id="decrementCounterInCache"
class="com.google.code.ssm.aop.counter.DecrementCounterInCacheAdvice">
<property name="cacheBase" ref="cacheBase" />
</bean>
<bean id="readCounterFromCache" class="com.google.code.ssm.aop.counter.ReadCounterFromCacheAdvice">
<property name="cacheBase" ref="cacheBase" />
</bean>
<bean id="updateCounterInCache" class="com.google.code.ssm.aop.counter.UpdateCounterInCacheAdvice">
<property name="cacheBase" ref="cacheBase" />
</bean>
</beans>
最常用的九大注解:
@ReadThroughSingleCache,@ReadThroughMultiCache,
@ReadThroughAssignCache,@InvalidateSingleCache,
@InvalidateMultiCache,@InvalidateAssignCache,
@UpdateSingleCache,@UpdateMultiCache,@UpdateAssignCache
按照操作类型分为:
read(读取)
@ReadThroughAssignCache(assignedKey = "SomePhatKey", namespace = "Echo", expiration = 3000): 读取指定key缓存
@ReadThroughSingleCache(namespace = SINGLE_NS, expiration = 0):读取单个缓存
@ReadThroughMultiCache(option = @ReadThroughMultiCacheOption(generateKeysFromResult = true)):读取多个缓存
@ReadThroughMultiCacheOption(generateKeysFromResult = true) 读取多个缓存操作generateKeysFromResult 通过结果生成key
Invalidate(失效)
@InvalidateAssignCache(assignedKey = "SomePhatKey", namespace = "Echo") : 指定key失效缓存
@InvalidateSingleCache(namespace = SINGLE_NS):失效单个缓存
@InvalidateMultiCache(namespace = "Delta") : 失效多个缓存
update(更新)
@UpdateAssignCache(assignedKey = "SomePhatKey", namespace = "Echo", expiration = 3000): 指定key更新缓存
@UpdateSingleCache(namespace = SINGLE_NS, expiration = 2): 更新单个缓存(namespace 命名空间, expiration 失效时间单位秒)
@UpdateMultiCache(namespace = "Bravo", expiration = 300): 更新多个缓存
按照操作对象分为:
SingleCache:操作单个POJO的Cache数据,由ParameterValueKeyProvider和 CacheKeyMethod提供标识组装key
MultiCache:读取多个缓存
AssignCache:注解指定key
@ReadThroughSingleCache
@ReadThroughSingleCache(namespace = "test" ,expiration = 3600)
public ObUsers getUsers(@ParameterValueKeyProvider long id){
return new ObUsers();
}
//多个数据生成key ,需要 order 属性
@ReadThroughSingleCache(namespace = "test" ,expiration = 3600)
public ObUsers getUsers2(@ParameterValueKeyProvider long id,
@ParameterValueKeyProvider(order = 1) String name){
return new ObUsers();
}
@ReadThroughMultiCache
@ReadThroughMultiCache(namespace = "userlist")
//expiration 不写,默认为0,会使用key值的默认过期时间
public ArrayList<ObUsers> getUserBaseInfo(@ParameterValueKeyProvider ArrayList<Long> idList) {
return null;
}
@ReadThroughMultiCache(option = @ReadThroughMultiCacheOption(generateKeysFromResult = true),
namespace = "userlist",expiration = 3600)
//generateKeysFromResult = TRUE 通过结果生成key
public ArrayList<ObUsers> getUserBaseInfo2(@ParameterValueKeyProvider ArrayList<Long> idList) {
return null;
}
@ReadThroughAssignCache
@ReadThroughAssignCache(assignedKey = "all",namespace = "test",expiration = 3600)
public ArrayList<ObUsers> getAll() { return null; }
@UpdateSingleCache
@UpdateSingleCache(namespace = "test", expiration = 3600)
@ReturnDataUpdateContent
//更新后的值成为缓存中的返回值
public ObUsers updateUsers(@ParameterValueKeyProvider long id) {
return new ObUsers();
}
@UpdateSingleCache(namespace = "test", expiration = 3600)
public ObUsers updateUsers2(@ParameterValueKeyProvider
@ParameterDataUpdateContent ObUsers user) {
return new ObUsers();
}
@UpdateMultiCache,@UpdateAssignCache
@UpdateMultiCache(namespace = "userlist")
@ReturnDataUpdateContent
public ArrayList<ObUsers> updateUserBaseInfo(@ParameterValueKeyProvider
ArrayList<Long> idList) {
return null;
}
@UpdateAssignCache(assignedKey = "all",namespace = "test")
public ArrayList<ObUsers> updateAll() { return null; }
@InvalidateSingleCache@InvalidateMultiCache@InvalidateAssignCache
@InvalidateSingleCache(namespace = "test")
@ReturnValueKeyProvider
public long removeUsers(@ParameterValueKeyProvider long id) {
return id;
}
@InvalidateMultiCache(namespace = "userlist")
public ArrayList<Long> removeUserBaseInfo(@ParameterValueKeyProvider
ArrayList<Long> idList) {
return idList;
}
@InvalidateAssignCache(assignedKey = "all",namespace = "test")
public ArrayList<ObUsers> removeAll() { return null; }
实体的定义
memcached相当于一个功能强大的Map,通过Key/Value的形式来缓存POJO实体,在定义实体的时候,可通过@CacheKeyMethod标签来为实体指定Key值,同时实体及实体的每个成员变量必须是可序列化的,可实现Serializable接口,或通过Externalizable接口来为实体指定序列化方法。
public class User implements Serializable {
private static final long serialVersionUID = 7517080513591583073L;
private String userId;
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@CacheKeyMethod
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
}
DAO的定义
缓存操作通常是对DAO的方法进行拦截,加入必要的通知以达到增删改查的效果切入点的声明主要通过之前提到的标签来实现
public class UserDaoImpl implements IUserDao {
private static final String NAMESPACE="ns";
private Map<String,User> users=new HashMap<String,User>();
@Override
public void saveUser(User user) {
users.put(user.getUserId(), user);
}
/**
* 当执行getById查询方法时,系统首先会从缓存中获取userId对应的实体
* 如果实体还没有被缓存,则执行查询方法并将查询结果放入缓存中
*/
@Override
@ReadThroughSingleCache(namespace = NAMESPACE, expiration = 3600)
public User getById(@ParameterValueKeyProvider String userId) {
System.out.println(userId);
return users.get(userId);
}
/**
* 当执行updateUser方法时,系统会更新缓存中userId对应的实体
* 将实体内容更新成@*DataUpdateContent标签所描述的实体
*/
@UpdateSingleCache(namespace = NAMESPACE, expiration = 3600)
@Override
public void updateUser(@ParameterValueKeyProvider @ParameterDataUpdateContent User user) {
users.put(user.getUserId(), user);
}
/**
* 当执行deleteUser方法时,系统会删除缓存中userId对应的实体
*/
@InvalidateSingleCache(namespace = NAMESPACE)
@Override
public void deleteUser(@ParameterValueKeyProvider String userId) {
users.remove(userId);
}
}
其他的一些注解
@ReadCounterFromCache :读取计数器
@IncrementCounterInCache: 计数器加一,如果不存在则初始化为1
@DecrementCOunterIncache: 计数器减一
@UpdateCounterIncache: 更新计数器@ParameterDataUpdateContent: 标记方法的参数作为更新内容。这个注解应结合Update*Cache注解使用
@ParameterValueKeyProvider: 标记将方法的参数做为计算缓存key.如果方法被注解的对象标记CacheKeyMethod的方法将会用来生成缓存key否则调用toString()生成
@ParameterValueKeyProvider(order=0) 属性表示如果多个参数做为key时需提供参数顺序