simple spring memcached(ssm) 和spring的整合教程 附代码

Memcached 是一个高性能的分布式内存对象缓存系统,在web应用中有很强大的应用场景。而spring作为一个流行的开源框架,在针对数据缓存中,也有着不少的需求。在众多的第三方实现中,google的simple-spring-memcached是一种非常好的方式。下面就用一个简单的订单系统,描述了在spring-mvc中使用memcached的集成方法。 

场景描述:a、用户在购买某件商品时,先进行商品的选择,系统生成商品的订单。订单内容包括:商品名称,商品id,订单id,商品原金额。

       b、用户进行订单确定,可能会有一定的折扣(例如使用京东的优惠券等),此时需要更新订单内容,订单内容需要更新商品的金额。

       c、用户需要选择支付方式,此时需要更新订单的支付渠道,同时还可能进行金额更新。(例如通过某宝搞活动等,呵呵)

     d、用户完成支付。

一旦做完了d,订单数据将进入交易数据库表中。

如果未做完d,每一步在30分钟之后,该笔订单就失效,并在memcached中删除订单。

 基于这个特性,abc状态的交易信息其实是交易信息的缓存,后面的增删改查如果每次都需要去进行数据库操作,是比较浪费的,因此考虑使用memcached进行订单状态的管理。

好了,需求大致落实好了,开干!

首先是在pom.xml完成与memcached相关的配置。(spring本身的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>

然后我们需要进行simple-spring-memcached的配置。

首先我们需要创建一个spring-memcached的基础配置文件,主要用于声明与spring相关的memcached配置。(例如命名空间等) 

<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"
    xmlns:aop="http://www.springframework.org/schema/aop" 
    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/aop
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <import resource="simplesm-context.xml" />

    <aop:aspectj-autoproxy />
    <context:annotation-config />
    <import resource="xmemcached.xml"/>
</beans>

这里我们可以看到,我们使用了一个xmemcached.xml的配置文件对memcached具体的内容进行配置。xmemcached.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" 
    xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean name="defaultMemcachedClient" class="com.google.code.ssm.CacheFactory">
        <!-- xmemcached配置方法 -->
        <property name="cacheClientFactory">
            <bean
                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="localhost:11211" />
            </bean>
        </property>  
        
        <!-- 定义了缓存节点的查找方法 -->
        <property name="configuration">
            <bean class="com.google.code.ssm.providers.CacheConfiguration">
                <property name="consistentHashing" value="true" />
            </bean>
        </property>
    </bean>

</beans>

到此步为止,我们的与memcached配置相关的xml已经完了,接下来开始编写我们的代码了。

首先创建一个类,用于缓存我们的订单信息,由于在memcached中是按照key-value形式进行数据存储的,因此我们需要指定一个key,这个key可以用注解来实现。

public class OrderInfo implements Serializable{
    /**
     * 
     */
    private static final long serialVersionUID = -608764679068384346L;
    
    private String orderId;
    private String productId;
    private String productName;
    private int productPrice;
    private int orderPrice;
    private String orderTime;
    private int paymentMethod;
    private int orderStatus;
    private String payTime;
    @CacheKeyMethod 
    public String getOrderId() {
        return orderId;
    }
    ...//get set method
}

 这里有两个注意点,首先,我们这个作为缓存信息的类,需要实现Serializable接口,否在在memcached中是无法缓存对象的。其次我要要指定一个索引key,我们这里使用了orderId作为可以的索引。

然后是我们的dao层。

public interface OrderInfoDao {
    public OrderInfo getOrderInfo(String orderId); 
    public void orderInit(OrderInfo orderInfo);
    public void orderChecks(OrderInfo orderInfo);
    public void orderPayChecks(OrderInfo orderInfo);
    public void orderSuccess(String orderId);
}

dao层相对来说比较简单,就不展开了。

最后是我们的关键了,dao层的实现,代码如下:

@Repository("orderInfoDao")
@ImportResource("classpath:spring_memcached.xml")
public class OrderInfoDaoImpl implements OrderInfoDao{

    private static final String ORDER_INFO_SSM = "orderInfoSSM";
    
    @ReadThroughSingleCache(namespace = ORDER_INFO_SSM, expiration = 1800)
    public OrderInfo getOrderInfo(@ParameterValueKeyProvider String orderId) {
        System.out.println("no cached hitd from ssm");
        return null;
    }
    @UpdateSingleCache(namespace = ORDER_INFO_SSM, expiration = 1800)
    public void orderInit(
            @ParameterValueKeyProvider @ParameterDataUpdateContent OrderInfo orderInfo) {
        System.out.println("orderInit cached to ssm");
        System.out.println(orderInfo.toString());
    }
    @UpdateSingleCache(namespace = ORDER_INFO_SSM, expiration = 1800)
    public void orderChecks(@ParameterValueKeyProvider @ParameterDataUpdateContent OrderInfo orderInfo) {
        System.out.println("orderChecks cached to ssm");
        System.out.println(orderInfo.toString());
        
    }
    @UpdateSingleCache(namespace = ORDER_INFO_SSM, expiration = 1800)
    public void orderPayChecks(@ParameterValueKeyProvider @ParameterDataUpdateContent OrderInfo orderInfo) {
        System.out.println("orderPayChecks cached to ssm");
        System.out.println(orderInfo.toString());
    }
    
    @InvalidateSingleCache(namespace = ORDER_INFO_SSM)  
    public void orderSuccess(@ParameterValueKeyProvider String orderId) {
        System.out.println("orderSuccess delet cached from ssm");
        System.out.println(orderId);
        //TODO 进行数据持久化处理
    }
}

首先我们要进行memcached命名空间的指定,通常来说,每个dao的实现都应在memcached中拥有自己的命名空间。

接下来简单描述下相关的注解:

@ReadThroughSingleCache 

1)、检查缓存中是否存在,如果存在,返回缓存数据并退出。

2)、如果在缓存中没有找到,将会继续访问下面的方法。

3)、如果方法返回了期望的对象,则memcached将会以注解ParameterValueKeyProvider修饰的对象作为key并把返回的对象记入缓存。

4)、如果方法没有发挥期望的对象,则memcached将不会写入该对象。

5)、expiration指定了失效时间,是以秒记的。

@UpdateSingleCache 

1)、用于更新缓存,包括两个概念,一是写入新的缓存,二是更新现有缓存。

2)、该注解中@ParameterDataUpdateContent代表更新之后进行对象刷新。

3)、由于我们之前在对象中使用了@CacheKeyMethod 的注解,因此我们这里可以直接使用该类进行写入,key就是对象中写的orderId。

@InvalidateSingleCache

这个注解就比较简单了,就是使缓存失效。

好了,大功告成,我们编写测试案例来试一下

@Test
    public void testSSM() throws InterruptedException {
        OrderInfo orderInfo = new OrderInfo();
        // step1 下订单,使用当前时间作为orderId
        String orderId = String.valueOf(System.currentTimeMillis());
        orderInfo.setOrderId(orderId);
        orderInfo.setOrderTime("20151125115900");
        orderInfo.setProductId("10000000");
        orderInfo.setProductName("apple phone 6s");
        orderInfo.setProductPrice(528800);
        orderInfoDao.orderInit(orderInfo);

        // step2 进行确定金额
        // 先从缓存中获取之前的数据,为了证明是从缓存中取出的,我们先初始化一下之前的对象
        orderInfo = null;
        orderInfo = orderInfoDao.getOrderInfo(orderId);
        System.out.println("get cached afterstep 1 orderInfo:" + orderInfo);
        orderInfo.setOrderStatus(2);
        // 更新金额,现在进行活动东,因此优惠288元
        orderInfo.setOrderPrice(500000);
        // 更新缓存
        orderInfoDao.orderChecks(orderInfo);

        // step3 进行支付方式选择
        // 先从缓存中获取之前的数据,为了证明是从缓存中取出的,我们先初始化一下之前的对象
        orderInfo = null;
        orderInfo = orderInfoDao.getOrderInfo(orderId);
        System.out.println("get cached afterstep 2 orderInfo:" + orderInfo);
        orderInfo.setOrderStatus(3);
        // 确定支付方式
        orderInfo.setPaymentMethod(1);
        // 支付方式继续进行优惠
        orderInfo.setPayPrice(480000);
        orderInfo.setPayTime("20151125120000");
        // 更新缓存
        orderInfoDao.orderPayChecks(orderInfo);

        // step4 进行支付
        // 先从缓存中获取之前的数据,为了证明是从缓存中取出的,我们先初始化一下之前的对象
        orderInfo = null;
        orderInfo = orderInfoDao.getOrderInfo(orderId);
        System.out.println("get cached afterstep 3 orderInfo:" + orderInfo);
        // TODO PAY action
        orderInfoDao.orderSuccess(orderInfo.getOrderId());

        // 确认缓存对象已经删除
        orderInfo = null;
        orderInfo = orderInfoDao.getOrderInfo(orderId);
        System.out.println("get cached afterstep 4 orderInfo:" + orderInfo);
    }

然后我们用maven-test观察下输出

orderInit cached to ssm
OrderInfo [orderId=1448455664090, productId=10000000, productName=apple phone 6s, productPrice=528800, orderPrice=0, orderTime=20151125115900, paymentMethod=0, payPrice=0, orderStatus=0, payTime=null]
get cached afterstep 1 orderInfo:OrderInfo [orderId=1448455664090, productId=10000000, productName=apple phone 6s, productPrice=528800, orderPrice=0, orderTime=20151125115900, paymentMethod=0, payPrice=0, orderStatus=0, payTime=null]
orderChecks cached to ssm
OrderInfo [orderId=1448455664090, productId=10000000, productName=apple phone 6s, productPrice=528800, orderPrice=500000, orderTime=20151125115900, paymentMethod=0, payPrice=0, orderStatus=2, payTime=null]
get cached afterstep 2 orderInfo:OrderInfo [orderId=1448455664090, productId=10000000, productName=apple phone 6s, productPrice=528800, orderPrice=500000, orderTime=20151125115900, paymentMethod=0, payPrice=0, orderStatus=2, payTime=null]
orderPayChecks cached to ssm
OrderInfo [orderId=1448455664090, productId=10000000, productName=apple phone 6s, productPrice=528800, orderPrice=500000, orderTime=20151125115900, paymentMethod=1, payPrice=480000, orderStatus=3, payTime=20151125120000]
get cached afterstep 3 orderInfo:OrderInfo [orderId=1448455664090, productId=10000000, productName=apple phone 6s, productPrice=528800, orderPrice=500000, orderTime=20151125115900, paymentMethod=1, payPrice=480000, orderStatus=3, payTime=20151125120000]
orderSuccess delet cached from ssm
1448455664090
no cached hitd from ssm
get cached afterstep 4 orderInfo:null
是不是很easy。
当然,实际上memcached通常回合数据库联合起来使用,例如在@ReadThroughSingleCache中使用访问数据库生成缓存,这里咱们的目的是memcached,就不再展开了,嘿嘿。
示例代码下载:
http://download.csdn.net/detail/highkgao1988/9300325




原文地址:https://www.cnblogs.com/highkgao/p/4989784.html