spring cache example

This commit is contained in:
sxyx2008
2014-07-29 16:07:44 +08:00
parent 80a677d653
commit d6f3fd68eb
12 changed files with 539 additions and 0 deletions
@@ -0,0 +1,60 @@
package org.spring.cache.example;
import java.io.Serializable;
@SuppressWarnings("serial")
public class Employee implements Serializable{
private int id;
private String empname;
private int age;
private String phone;
public Employee() {
}
public Employee(int id, String empname, int age, String phone) {
super();
this.id = id;
this.empname = empname;
this.age = age;
this.phone = phone;
}
public Employee(String empname) {
super();
this.empname = empname;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getEmpname() {
return empname;
}
public void setEmpname(String empname) {
this.empname = empname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "Employee [id=" + id + ", empname=" + empname + ", age=" + age
+ ", phone=" + phone + "]";
}
}
@@ -0,0 +1,90 @@
package org.spring.cache.example;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@Service
public class EmployeeService {
Logger logger = LoggerFactory.getLogger(getClass());
/**
* @Cacheable:负责将方法的返回值加入到缓存中
*
* @CacheEvict:负责清除缓存
*
* @Cacheable 支持如下几个参数:
*
* value:缓存位置名称,不能为空,如果使用EHCache,就是ehcache.xml中声明的cache的name
*
* key:缓存的key,默认为空,既表示使用方法的参数类型及参数值作为key,支持SpEL
*
* condition:触发条件,只有满足条件的情况才会加入缓存,默认为空,既表示全部都加入缓存,支持SpEL
*
* @CacheEvict 支持如下几个参数:
*
* value:缓存位置名称,不能为空,同上
*
* key:缓存的key,默认为空,同上
*
* condition:触发条件,只有满足条件的情况才会清除缓存,默认为空,支持SpEL
*
* allEntries:true表示清除value中的全部缓存,默认为false
*/
@Cacheable(value = "employeeCache"/*,condition="#empname.length() <= 4"*/)
// 使用了一个缓存名叫 employeeCache
public Employee getEmployeeByName(String empname) {
// 方法内部实现不考虑缓存逻辑,直接实现业务
return getFromDB(empname);
}
@Cacheable(value = "employeeCache", key = "#id")
// 使用了一个缓存名为employeeCache的缓存
public String getEmployee(Integer id) {
logger.info("get employee called " + id);
return "getEmployee" + id;
}
@Cacheable(value = "employeeCache", key = "#id", condition = "#id <= 10")
// 使用了一个缓存名为employeeCache的缓存,缓存id小于等于10
public String findEmployee(Integer id) {
logger.info("get employee called");
return "findEmployee" + id;
}
@CacheEvict(value = "employeeCache", allEntries = true)
public List<Employee> listEmployee() {
List<Employee> emps = new ArrayList<Employee>();
return emps;
}
@CachePut(value = "employeeCache", key = "#employee.getEmpname()")
// 清空 employeeCache 缓存
public void updateEmployee(Employee employee) {
updateDB(employee);
}
@CacheEvict(value = "employeeCache", allEntries = true)
// 清空 employeeCache 缓存
public void reload() {
}
private Employee getFromDB(String empname) {
System.out.println("real querying db..." + empname);
return new Employee(empname);
}
private void updateDB(Employee employee) {
System.out.println("real update db..." + employee.getEmpname());
}
}
@@ -0,0 +1,22 @@
package org.spring.cache.example;
import java.util.HashMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class WebController {
@Autowired
EmployeeService employeeService;
@RequestMapping("/index.htm")
public String homePage(@RequestParam(required = false) Integer id,
HashMap<String, String> map) {
map.put("message", employeeService.getEmployee(id));
return "index";
}
}
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<diskStore path="java.io.tmpdir" />
<cache name="employeeCache" maxElementsInMemory="10000" eternal="false"
timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
maxElementsOnDisk="10000000" diskPersistent="false"
diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" />
</ehcache>
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//LOGGER"
"http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd">
<log4j:configuration>
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
<!--<param name="Threshold" value="WARN"/>-->
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %d{ISO8601} [%C.%M - %t] [%x] - %m%n"/>
</layout>
</appender>
<appender name="LOGFILE" class="org.apache.log4j.RollingFileAppender">
<!-- <param name="Threshold" value="INFO" /> -->
<!-- <param name="Append" value="false" /> -->
<param name="MaxBackupIndex" value="5"/>
<param name="MaxFileSize" value="10MB"/>
<param name="File" value="target/log4j.log"/>
<layout class="org.apache.log4j.PatternLayout">
<!-- <param name="ConversionPattern" value="%-4r [%C.%M - %t] %-5p [%x] - %m%n" /> -->
<param name="ConversionPattern" value="%-5p %d [%t] %c: %m%n"/>
</layout>
</appender>
<logger name="org.spring.cache.example">
<level value="DEBUG"/>
</logger>
<logger name="org.springframework.web.accept">
<level value="WARN"/>
</logger>
<logger name="org.springframework">
<level value="WARN"/>
</logger>
<root>
<level value="WARN"/>
<appender-ref ref="CONSOLE"/>
</root>
</log4j:configuration>
@@ -0,0 +1,57 @@
<?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:cache="http://www.springframework.org/schema/cache"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd">
<!-- Scans within the base package of the application for @Components to
configure as beans -->
<context:component-scan base-package="org.spring.cache.example" />
<!-- Process cache annotations -->
<cache:annotation-driven cache-manager="cacheManager"/>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass">
<value>org.springframework.web.servlet.view.JstlView</value>
</property>
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- Configuration for using Ehcache as the cache manager -->
<!-- 使用ehcache配置缓存 -->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cache-manager-ref="ehcache" />
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:config-location="classpath:ehcache.xml" p:shared="true"/>
<!-- Configuration for using SimpleCacheManager as the cache manager -->
<!-- 使用Spring默认的缓存方案SimpleCacheManager,其内部使用了缺省的内存存储方案 ConcurrentMapCacheFactoryBean,它是基于 java.util.concurrent.ConcurrentHashMap 的一个内存缓存实现方案。 -->
<!--
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean
class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"
p:name="default" />
<bean
class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"
p:name="employeeCache" />
</set>
</property>
</bean>
-->
</beans>
@@ -0,0 +1,12 @@
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Cache Example</title>
</head>
<body>
<h1>This is ${message }</h1>
</body>
</html>
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>sample</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>sample</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
@@ -0,0 +1,72 @@
package org.spring.cache.example;
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.SpringJUnit4ClassRunner;
@ContextConfiguration(locations = "file:src/main/webapp/WEB-INF/applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class EmployeeServiceTest {
@Autowired
EmployeeService employeeService;
@Test
public void getEmployee() {
employeeService.getEmployee(1);
employeeService.getEmployee(1);
employeeService.getEmployee(2);
employeeService.getEmployee(2);
employeeService.getEmployee(3);
employeeService.getEmployee(3);
}
@SuppressWarnings("unused")
@Test
public void testCache() {
// 第一次查询,应该走数据库
System.out.print("first query...");
employeeService.getEmployeeByName("somebody");
// 第二次查询,应该不查数据库,直接返回缓存的值
System.out.print("second query...");
employeeService.getEmployeeByName("somebody");
System.out.println();
System.out.println("start testing clear cache..."); // 更新某个记录的缓存,首先构造两个账号记录,然后记录到缓存中
Employee employee1 = employeeService.getEmployeeByName("somebody1");
Employee employee2 = employeeService.getEmployeeByName("somebody2");
// 开始更新其中一个
employee1.setId(1212);
employeeService.updateEmployee(employee1);
employeeService.getEmployeeByName("somebody1");// 因为被更新了,所以会查询数据库
employeeService.getEmployeeByName("somebody2");// 没有更新过,应该走缓存
employeeService.getEmployeeByName("somebody1");// 再次查询,应该走缓存 // 更新所有缓存
employeeService.reload();
employeeService.getEmployeeByName("somebody1");// 应该会查询数据库
employeeService.getEmployeeByName("somebody2");// 应该会查询数据库
employeeService.getEmployeeByName("somebody1");// 应该走缓存
employeeService.getEmployeeByName("somebody2");// 应该走缓存
}
@Test
public void testCacheCondition() {
employeeService.getEmployeeByName("somebody");// 长度大于 4,不会被缓存
employeeService.getEmployeeByName("sbd");// 长度小于 4,会被缓存
employeeService.getEmployeeByName("somebody");// 还是查询数据库
employeeService.getEmployeeByName("sbd");// 会从缓存返回
}
@Test
public void testCachePut() {
Employee employee = employeeService.getEmployeeByName("someone");
employee.setAge(18);
employeeService.updateEmployee(employee);
employee.setAge(28);
employeeService.updateEmployee(employee);
employee = employeeService.getEmployeeByName("someone");
System.out.println(employee.getEmpname());
}
}