近期公司的产品重构,底层使用了memcached 作为缓存系统,使用了几天之后发现每次增删查改之后都要手动进行更新缓存,为了偷懒,在网上查了查,发现使用SSM开源项目可以很方便的通过几个注解进行管理缓存。其实原理也很简单,主要利用了spring 的AOP编程,现在简单介绍下是如何实现的。
首先,在你的项目工程的pom.xml文件中添加以下依赖,ssm针对不同的memcached 客户端需要添加不同的实现
这是针对xmemcached 客户端
<dependency>
<groupId>com.google.code.simple-spring-memcached</groupId>
<artifactId>xmemcached-provider</artifactId>
<version>3.1.0</version>
</dependency>
这是针对spymemcached客户端
<dependency>
<groupId>com.google.code.simple-spring-memcached</groupId>
<artifactId>spymemcached-provider</artifactId>
<version>3.1.0</version>
</dependency>
这是我的数据库实体类:HUser.java
package com.mailbill.datacore.entity;
import java.io.Serializable;
import java.util.Date;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import com.google.code.ssm.api.CacheKeyMethod;
/**
* auto create pojo
* @author mycode
* @version 1.0
*/
@JsonIgnoreProperties(ignoreUnknown=true)
public class Huser implements Saveable,Serializable{
private static final long serialVersionUID = 1L;
private static final String[] keyColumns = { "h_userid" };
private static final String TABLENAME = "huser";
@Override
public String getTableName() {
return TABLENAME;
}
@Override
public String[] getKeyColumns() {
return keyColumns;
}
private long h_userid = 0;
@CacheKeyMethod
public long geth_userid(){
return h_userid;
}
public void seth_userid(long h_userid){
this.h_userid = h_userid;
}
private String h_name = "";
public String geth_name(){
return h_name;
}
public void seth_name(String h_name){
this.h_name = h_name;
}
private int h_age = 0;
public int geth_age(){
return h_age;
}
public void seth_age(int h_age){
this.h_age = h_age;
}
@CacheKeyMethod
public String getCacheKey(){
return "huser_"+geth_userid();
}
@Override
public String toString() {
// TODO Auto-generated method stub
return h_name+":"+h_userid+":"+h_age;
}
}
可以看到geth_userid 方法上声明了一个注释:@CacheKeyMethod,这个是用来标识memcached 进行缓存操作时获取key的方法。
我的Dao类中的相关方法如下:
@ReadThroughSingleCache(namespace="user")
public Huser getHuserById(@ParameterValueKeyProvider long id) throws Exception{
String sql = "select * from huser where h_userid=?";
System.out.println("没有缓存命中");
return (Huser) queryOne(sql,new Object[]{id}, new Huser());
}
@UpdateSingleCache(namespace="user")
public int modHuser(@ParameterValueKeyProvider @ParameterDataUpdateContent Huser entity) throws Exception{
return modify(entity);
}
@InvalidateSingleCache(namespace="user")
public int delUser(@ParameterValueKeyProvider long key) throws Exception {
String sql = "delete from huser where h_userid=?";
return delete(sql,new Object[]{key});
}
可以看到上面三个方法中有几个注释,现在分别对上面几个注释进行简单的介绍下:
@ReadThroughSingleCache
作用:读取Cache中数据,如果不存在,则将读取的数据存入Cache
key生成规则:ParameterValueKeyProvider指定的参数,如果该参数对象中包含CacheKeyMethod注解的方法,则调用其方法,否则调用toString方法
@InvalidateSingleCache
作用:失效Cache中的数据
key生成规则:
使用 ParameterValueKeyProvider注解时,与ReadThroughSingleCache一致
@UpdateSingleCache
作用:更新Cache中的数据
key生成规则:ParameterValueKeyProvider指定
ParameterDataUpdateContent:方法参数中的数据,作为更新缓存的数据
除了以上几种注释之外,SSM还提供了一些其它的注释,可以参孝下文
http://www.colorfuldays.org/program/java/ssm_memcache/
现在看看spring的配置文件:memcached-spring.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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<import resource="simplesm-context.xml" />
<context:property-placeholder location="classpath:memcached.properties" ignore-unresolvable="true"/>
<aop:aspectj-autoproxy />
<bean name="defaultMemcachedClient" class="com.google.code.ssm.CacheFactory">
<property name="cacheClientFactory">
<bean name="cacheClientFactory" class="com.google.code.ssm.providers.xmemcached.MemcacheClientFactoryImpl" />
</property>
<property name="addressProvider">
<bean class="com.google.code.ssm.config.DefaultAddressProvider">
<!-- memcached 服务器地址,可配置多个,用“,”号隔开 -->
<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>
<!-- 该Memcached配置的Cache名称 一个应用中存在多个Memcached时,各个配置的cacheName必须不同。如果该值未设,系统默认为default
<property name="cacheName" value="mailbill"/>-->
</bean>
</beans>
基本的配置及代码就写完了,现在写几个测试方法测试一下;MemcachedTest.java
package com.mailbill;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.mailbill.datacore.dao.HuserDao;
import com.mailbill.datacore.entity.Huser;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext-jdbc-base.xml")
public class MemcachedTest extends AbstractJUnit4SpringContextTests {
@Autowired
private HuserDao dao;
@Test
public void save(){
Huser user = new Huser();
user.seth_name("hahah");
user.seth_age(21);
try {
long userid = dao.addHuser(user);
System.out.println(userid);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Test
public void get(){
try {
Huser user = dao.getHuserById(1);
System.out.println(user);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Test
public void update(){
try {
Huser user = dao.getHuserById(2);
user.seth_age(24);
user.seth_name("xiaolongnv");
dao.modHuser(user);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Test
public void delete(){
try {
dao.delUser(2);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
测试的时候可以使用MemcacheD Manager 工具进行监控memcached 的缓存状态,如图: