注:此文參考並整合了網上的文章
《spring緩存機制》:http://blog.csdn.net/sidongxue2/article/details/30516141
《配置 Spring4.0 注解Cache+Redis緩存》:http://blog.csdn.net/ouyhong123/article/details/52162951
《spring整合redis緩存,以注解(@Cacheable、@CachePut、@CacheEvict)形式使用》: http://blog.csdn.net/aqsunkai/article/details/51758900
因為是自己簡單搭建的例子,所以一個高級配置(如緩存規則)都沒有加。
整個目錄的結構如下:
幾個重點的文件代碼如下:
pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zjf</groupId>
<artifactId>springmvc</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.7.2.RELEASE</version>
</dependency>
</dependencies>
</project>
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="3.0"
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_3_0.xsd">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/config/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/config/spring-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
spring-servlet.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"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"
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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 配置掃描的包 -->
<context:component-scan base-package="com.zjf.*" />
<!-- 注冊HandlerMapper、HandlerAdapter兩個映射類 -->
<mvc:annotation-driven />
<!-- 訪問靜態資源 -->
<mvc:default-servlet-handler />
<!-- 視圖解析器 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
applicationContext.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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache-4.2.xsd">
<!-- 應用spring cache注解功能 -->
<cache:annotation-driven />
<context:property-placeholder location="classpath:redis.properties" />
<!-- jedis 配置 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}" />
<!--<property name="maxWaitMillis" value="${redis.maxWait}" />-->
<property name="testOnBorrow" value="${redis.testOnBorrow}" />
</bean>
<!-- redis服務器中心 -->
<bean id="connectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="poolConfig" ref="poolConfig" />
<property name="port" value="${redis.port}" />
<property name="hostName" value="${redis.hostname}" />
<!-- <property name="password" value="${redis.password}" /> -->
<property name="timeout" value="${redis.timeout}"></property>
</bean>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="connectionFactory" />
<property name="keySerializer">
<bean
class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="valueSerializer">
<bean
class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
</property>
</bean>
<!-- 創建spring cache bean -->
<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="com.zjf.util.RedisCache">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="data"/>
<!-- common名稱要在類或方法的注解中使用 -->
</bean>
</set>
</property>
</bean>
<!-- 創建User Dao bean -->
<bean id="userDao" class="com.zjf.spring.cache.dao.impl.UserDaoImpl" ></bean>
<!-- 創建User Service bean -->
<bean id="userService" class="com.zjf.spring.cache.service.impl.UserServiceImpl" >
<property name="userDao" >
<ref bean="userDao"></ref>
</property>
</bean>
</beans>
UserServiceImpl.java:
package com.zjf.spring.cache.service.impl;
import java.util.Map;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import com.zjf.spring.cache.dao.UserDao;
import com.zjf.spring.cache.model.User;
import com.zjf.spring.cache.service.UserService;
public class UserServiceImpl implements UserService {
private UserDao userDao;
/**
* JVM加載spring配置文件時, 通過set方法注入本類的依賴.
* @param userDao
*/
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
/**
* 對數據進行增刪改時清空緩存, 查詢時使用緩存, 其中value為緩存區,
* allEntries表示清空緩存中所有的數據.
*/
@CacheEvict(value = "data", allEntries = true)
public void add(User user) {
System.out.println("UserService: method- add(User user)" );
userDao.add(user);
}
@CacheEvict(value = "data", allEntries = true)
public void delete(String id) {
System.out.println("UserService: method-delete(String id)" );
userDao.delete(id);
}
@CacheEvict(value = "data", allEntries = true)
public void update(User user) {
System.out.println("UserService: method-update(User user)" );
userDao.update(user);
}
@Cacheable(value = "data")
public User find(String id) {
System.out.println("UserService: method-find(String id)" );
return userDao.find(id);
}
@Cacheable(value = "data")
public Map<String, User> getAll() {
System.out.println("UserService: method-getAll()" );
return userDao.getAll();
}
}
redis.properties
#redis config
#redis.hostname=192.168.242.131
redis.hostname=192.168.1.101
redis.port=6379
redis.timeout=2000
redis.usePool=true
redis.default.db=0
#\u6700\u5927\u5206\u914D\u7684\u5BF9\u8C61\u6570
redis.maxTotal=600
#\u6700\u5927\u80FD\u591F\u4FDD\u6301idel\u72B6\u6001\u7684\u5BF9\u8C61\u6570
redis.maxIdle=300
#\u591A\u957F\u65F6\u95F4\u68C0\u67E5\u4E00\u6B21\u8FDE\u63A5\u6C60\u4E2D\u7A7A\u95F2\u7684\u8FDE\u63A5
redis.timeBetweenEvictionRunsMillis=30000
#\u7A7A\u95F2\u8FDE\u63A5\u591A\u957F\u65F6\u95F4\u540E\u4F1A\u88AB\u6536\u56DE
redis.minEvictableIdleTimeMillis=30000
#\u5F53\u8C03\u7528borrow Object\u65B9\u6CD5\u65F6\uFF0C\u662F\u5426\u8FDB\u884C\u6709\u6548\u6027\u68C0\u67E5
redis.testOnBorrow=true
########reids\u7F16\u7801\u683C\u5F0F
redis.encode=utf-8
######\u7F13\u5B58\u8FC7\u671F\u65F6\u95F4 \u79D2 1000*60*60*24*7 \u4E03\u5929
redis.expire=604800000
####\u662F\u5426\u5F00\u542FRedis\u670D\u52A1\u5E94\u7528
redis.unlock=false
DemoController.java:
package com.zjf.spring.cache;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.zjf.spring.cache.model.User;
import com.zjf.spring.cache.service.UserService;
@Controller
public class DemoController {
@Autowired
private UserService userService;
@RequestMapping("/finduser")
public String finduser() {
User user = userService.find("2");
System.out.println(user);
return "finduser";
}
@RequestMapping("/adduser")
public String adduser() {
userService.add(new User("2", "Ilucky1", "pwd1"));
return "adduser";
}
}
執行結果:
tomcat服務啟動后,先進入http://localhost:8080/springmvc/adduser頁面,這時候會在dao層插入一個user。
然后進入http://localhost:8080/springmvc/finduser頁面,因為第一次進入,還沒有緩存,這時候會進入service和dao。
再次進入http://localhost:8080/springmvc/finduse 頁面,這個時候發現,沒有進入service。直接取了redis緩存。
控制台打印的結果如下:
UserService: method- add(User user)
UserDao method- add(User user)
UserService: method-find(String id)
UserDao method- find(String id)
2-Ilucky1-pwd1
2-Ilucky1-pwd1
注意:第二次打印2-Ilucky1-pwd1的時候,前面沒有進入UserService和UserDao的打印。
這個時候我們去redis服務器上看redis的緩存。
127.0.0.1:6379> keys *
1) "2"
注意:keys*命令可以獲取所有的key。這里我們看到key為2.因為我們執行UserService: method-find(String id)方法的時候,傳入的參數是2.這樣來看,spring是通過參數來作為key的,如果有兩個不同的方法,參數一樣,那么緩存會沖突才對。所以還是定義@Cacheable注解的時候,還是把key也加上。
@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”) |
------------------------------------------------------------
表 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”) |
//////////////////////////////////////////////////////
表 3. @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) |
整個代碼的下載:
http://download.csdn.net/detail/xiaolang8762400/9857058