diff --git a/pom.xml b/pom.xml
index 429e41d..16f8379 100644
--- a/pom.xml
+++ b/pom.xml
@@ -93,6 +93,7 @@
json-tutorials
hibernate-tutorials
commons-dbutils-tutorial
+ spring-cache-example
spring-jdbc-tutorials
spring-data-example
spring-ibatis-example
diff --git a/spring-cache-example/README.md b/spring-cache-example/README.md
new file mode 100644
index 0000000..91d176b
--- /dev/null
+++ b/spring-cache-example/README.md
@@ -0,0 +1,79 @@
+# spring-cache-example
+
+基于注解(@Cacheable)的spring cache
+
+需要使用``或`@EnableCaching`开启缓存
+
+### 1. 使用ehcache
+
+```
+
+
+
+```
+
+### 2. 使用spring内置的默认实现基于JDK的ConcurrentMap
+
+```
+
+
+
+
+
+
+
+
+```
+
+### @Cacheable、@CachePut、@CacheEvict 注释介绍
+
+@Cacheable 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存
+
+@Cacheable 主要的参数
+
+```
+value 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 例如:@Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”}
+key 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 例如:@Cacheable(value=”testcache”,key=”#userName”)
+condition 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 例如:@Cacheable(value=”testcache”,condition=”#userName.length()>2”)
+```
+
+@CachePut 作用和配置方法
+
+@CachePut 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实方法的调用
+
+@CachePut 主要的参数
+
+```
+value 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 例如:@Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”}
+key 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 例如:@Cacheable(value=”testcache”,key=”#userName”)
+condition 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 例如:@Cacheable(value=”testcache”,condition=”#userName.length()>2”)
+```
+
+@CacheEvict 作用和配置方法
+
+@CachEvict 的作用 主要针对方法配置,能够根据一定的条件对缓存进行清空
+
+@CacheEvict 主要的参数
+
+```
+value 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 例如:@CachEvict(value=”mycache”) 或者 @CachEvict(value={”cache1”,”cache2”}
+key 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 例如:@CachEvict(value=”testcache”,key=”#userName”)
+condition 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才清空缓存 例如:@CachEvict(value=”testcache”,condition=”#userName.length()>2”)
+allEntries 是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存 例如:@CachEvict(value=”testcache”,allEntries=true)
+beforeInvocation 是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存 例如:@CachEvict(value=”testcache”,beforeInvocation=true)
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-cache-example/pom.xml b/spring-cache-example/pom.xml
new file mode 100644
index 0000000..ff05c15
--- /dev/null
+++ b/spring-cache-example/pom.xml
@@ -0,0 +1,73 @@
+
+
+ 4.0.0
+
+ net.aimeizi
+ maven-framework-project
+ 1.0.0
+
+ spring-cache-example
+ war
+ spring-cache-example
+ http://maven.apache.org
+
+ UTF-8
+
+
+
+
+ servlet-api
+ javax.servlet
+ 2.5
+ provided
+
+
+ jstl
+ jstl
+ 1.2
+
+
+ org.springframework
+ spring-context-support
+ 3.2.5.RELEASE
+
+
+ org.springframework
+ spring-webmvc
+ 3.2.5.RELEASE
+
+
+ org.slf4j
+ slf4j-log4j12
+ 1.7.5
+
+
+ net.sf.ehcache
+ ehcache
+ 2.7.0
+
+
+ org.springframework
+ spring-test
+ 3.2.5.RELEASE
+
+
+ junit
+ junit
+ 4.11
+
+
+
+
+
+
+ org.apache.tomcat.maven
+ tomcat7-maven-plugin
+ 2.1
+
+
+
+
+
diff --git a/spring-cache-example/src/main/java/org/spring/cache/example/Employee.java b/spring-cache-example/src/main/java/org/spring/cache/example/Employee.java
new file mode 100644
index 0000000..a5917d0
--- /dev/null
+++ b/spring-cache-example/src/main/java/org/spring/cache/example/Employee.java
@@ -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 + "]";
+ }
+
+}
diff --git a/spring-cache-example/src/main/java/org/spring/cache/example/EmployeeService.java b/spring-cache-example/src/main/java/org/spring/cache/example/EmployeeService.java
new file mode 100644
index 0000000..5e2d26e
--- /dev/null
+++ b/spring-cache-example/src/main/java/org/spring/cache/example/EmployeeService.java
@@ -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 listEmployee() {
+ List emps = new ArrayList();
+ 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());
+ }
+
+}
diff --git a/spring-cache-example/src/main/java/org/spring/cache/example/WebController.java b/spring-cache-example/src/main/java/org/spring/cache/example/WebController.java
new file mode 100644
index 0000000..a07e80b
--- /dev/null
+++ b/spring-cache-example/src/main/java/org/spring/cache/example/WebController.java
@@ -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 map) {
+ map.put("message", employeeService.getEmployee(id));
+ return "index";
+ }
+}
diff --git a/spring-cache-example/src/main/resources/ehcache.xml b/spring-cache-example/src/main/resources/ehcache.xml
new file mode 100644
index 0000000..37cb264
--- /dev/null
+++ b/spring-cache-example/src/main/resources/ehcache.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-cache-example/src/main/resources/log4j.xml b/spring-cache-example/src/main/resources/log4j.xml
new file mode 100644
index 0000000..61d1a88
--- /dev/null
+++ b/spring-cache-example/src/main/resources/log4j.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-cache-example/src/main/webapp/WEB-INF/applicationContext.xml b/spring-cache-example/src/main/webapp/WEB-INF/applicationContext.xml
new file mode 100644
index 0000000..f42add3
--- /dev/null
+++ b/spring-cache-example/src/main/webapp/WEB-INF/applicationContext.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+ org.springframework.web.servlet.view.JstlView
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-cache-example/src/main/webapp/WEB-INF/views/index.jsp b/spring-cache-example/src/main/webapp/WEB-INF/views/index.jsp
new file mode 100644
index 0000000..f3c5918
--- /dev/null
+++ b/spring-cache-example/src/main/webapp/WEB-INF/views/index.jsp
@@ -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" %>
+
+
+
+
+Cache Example
+
+
+ This is ${message }
+
+
\ No newline at end of file
diff --git a/spring-cache-example/src/main/webapp/WEB-INF/web.xml b/spring-cache-example/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..29a212f
--- /dev/null
+++ b/spring-cache-example/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ sample
+
+ org.springframework.web.servlet.DispatcherServlet
+
+
+ contextConfigLocation
+ /WEB-INF/applicationContext.xml
+
+ 1
+
+
+
+ sample
+ /
+
+
+
\ No newline at end of file
diff --git a/spring-cache-example/src/test/java/org/spring/cache/example/EmployeeServiceTest.java b/spring-cache-example/src/test/java/org/spring/cache/example/EmployeeServiceTest.java
new file mode 100644
index 0000000..1e662a2
--- /dev/null
+++ b/spring-cache-example/src/test/java/org/spring/cache/example/EmployeeServiceTest.java
@@ -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());
+ }
+
+}