本文章牽涉到的技術點比較多:spring Data JPA、Redis、Spring MVC,Spirng Cache,所以在看這篇文章的時候,需要對以上這些技術點有一定的了解或者也可以先看看這篇文章,針對文章中實際的技術點在進一步了解(注意,您需要自己下載Redis Server到您的本地,所以確保您本地的Redis可用,這里還使用了MySQL數據庫,當然你也可以內存數據庫進行測試)。這篇文章會提供對應的Eclipse代碼示例,具體大體的分如下幾個步驟:
(1)新建Java MavenProject;
(2)在pom.xml中添加相應的依賴包;
(3)編寫Spring Boot啟動類;
(4)配置application.properties;
(5)編寫RedisCacheConfig配置類;
(6)編寫DemoInfo測試實體類;
(7)編寫DemoInfoRepository持久化類;
(8)編寫DemoInfoService類;
(9)編寫DemoInfoController類;
(10)測試代碼是否正常運行了
(11)自定義緩存key;
接下來我們看看具體每個步驟具體的操作吧。
(1)新建Java Maven Project;
這個步驟就不細說,新建一個spring-boot-redis Java mavenproject;
(2)在pom.xml中添加相應的依賴包;
在Maven中添加相應的依賴包,主要有:springboot 父節點依賴;spring boot web支持;緩存服務spring-context-support;添加redis支持;JPA操作數據庫;mysql 數據庫驅動,具體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.0http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.kfit</groupId>
<artifactId>spring-boot-redis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-boot-redis</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 配置JDK編譯版本. -->
<java.version>1.8</java.version>
</properties>
<!-- spring boot 父節點依賴,
引入這個之后相關的引入就不需要添加version配置,
spring boot會自動選擇最合適的版本進行添加。
-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- springboot web支持:mvc,aop... -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--
包含支持UI模版(Velocity,FreeMarker,JasperReports),
郵件服務,
腳本服務(JRuby),
緩存Cache(EHCache),
任務計划Scheduling(uartz)。
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<!-- 添加redis支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
</dependency>
<!-- JPA操作數據庫. -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- mysql數據庫驅動. -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 單元測試. -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
上面是完整的pom.xml文件,每個里面都進行了簡單的注釋。
(3)編寫Spring Boot啟動類(com.kfit.App);
package com.kfit;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Spring Boot啟動類;
*
* @authorAngel(QQ:412887952)
* @version v.0.1
*/
@SpringBootApplication
public class App {
/**
*-javaagent:.\lib\springloaded-1.2.4.RELEASE.jar -noverify
* @param args
*/
public static voidmain(String[] args) {
SpringApplication.run(App.class,args);
}
}
(4)配置application.properties;
這里主要是配置兩個資源,第一就是數據庫基本信息;第二就是redis配置;第三就是JPA的配置;
Src/main/resouces/application.properties:
########################################################
###datasource 配置MySQL數據源;
########################################################
spring.datasource.url =jdbc:mysql://localhost:3306/test
spring.datasource.username = root
spring.datasource.password = root
spring.datasource.driverClassName =com.mysql.jdbc.Driver
spring.datasource.max-active=20
spring.datasource.max-idle=8
spring.datasource.min-idle=8
spring.datasource.initial-size=10
########################################################
###REDIS (RedisProperties) redis基本配置;
########################################################
# database name
spring.redis.database=0
# server host1
spring.redis.host=127.0.0.1
# server password
#spring.redis.password=
#connection port
spring.redis.port=6379
# pool settings ...
spring.redis.pool.max-idle=8
spring.redis.pool.min-idle=0
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=-1
# name of Redis server
#spring.redis.sentinel.master=
# comma-separated list of host:portpairs
#spring.redis.sentinel.nodes=
########################################################
### Java Persistence Api 自動進行建表
########################################################
# Specify the DBMS
spring.jpa.database = MYSQL
# Show or not log for each sqlquery
spring.jpa.show-sql = true
# hibernate ddl auto (create,create-drop, update)
spring.jpa.hibernate.ddl-auto = update
# Naming strategy
spring.jpa.hibernate.naming-strategy =org.hibernate.cfg.ImprovedNamingStrategy
# stripped before adding them tothe entity manager)
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
(5)編寫RedisCacheConfig配置類;
緩存主要有幾個要實現的類:其一就是CacheManager緩存管理器;其二就是具體操作實現類;其三就是CacheManager工廠類(這個可以使用配置文件配置的進行注入,也可以通過編碼的方式進行實現);其四就是緩存key生產策略(當然Spring自帶生成策略,但是在Redis客戶端進行查看的話是系列化的key,對於我們肉眼來說就是感覺是亂碼了,這里我們先使用自帶的緩存策略)。
com.kfit.config/RedisCacheConfig:
package com.kfit.config;
importorg.springframework.cache.CacheManager;
importorg.springframework.cache.annotation.CachingConfigurerSupport;
importorg.springframework.cache.annotation.EnableCaching;
importorg.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
importorg.springframework.data.redis.cache.RedisCacheManager;
importorg.springframework.data.redis.connection.RedisConnectionFactory;
importorg.springframework.data.redis.core.RedisTemplate;
/**
* redis 緩存配置;
*
* 注意:RedisCacheConfig這里也可以不用繼承 :CachingConfigurerSupport,也就是直接一個普通的Class就好了;
*
* 這里主要我們之后要重新實現 key的生成策略,只要這里修改KeyGenerator,其它位置不用修改就生效了。
*
* 普通使用普通類的方式的話,那么在使用@Cacheable的時候還需要指定KeyGenerator的名稱;這樣編碼的時候比較麻煩。
*
* @author Angel(QQ:412887952)
* @version v.0.1
*/
@Configuration
@EnableCaching //啟用緩存,這個注解很重要;
public class RedisCacheConfig extendsCachingConfigurerSupport {
/**
* 緩存管理器.
* @param redisTemplate
* @return
*/
@Bean
public CacheManagercacheManager(RedisTemplate<?,?> redisTemplate) {
CacheManagercacheManager = newRedisCacheManager(redisTemplate);
return cacheManager;
}
/**
* redis模板操作類,類似於jdbcTemplate的一個類;
*
* 雖然CacheManager也能獲取到Cache對象,但是操作起來沒有那么靈活;
*
* 這里在擴展下:RedisTemplate這個類不見得很好操作,我們可以在進行擴展一個我們
*
* 自己的緩存類,比如:RedisStorage類;
*
* @param factory : 通過Spring進行注入,參數在application.properties進行配置;
* @return
*/
@Bean
publicRedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String,String> redisTemplate = new RedisTemplate<String, String>();
redisTemplate.setConnectionFactory(factory);
//key序列化方式;(不然會出現亂碼;),但是如果方法上有Long等非String類型的話,會報類型轉換錯誤;
//所以在沒有自己定義key生成策略的時候,以下這個代碼建議不要這么寫,可以不配置或者自己實現ObjectRedisSerializer
//或者JdkSerializationRedisSerializer序列化方式;
// RedisSerializer<String>redisSerializer = new StringRedisSerializer();//Long類型不可以會出現異常信息;
// redisTemplate.setKeySerializer(redisSerializer);
// redisTemplate.setHashKeySerializer(redisSerializer);
return redisTemplate;
}
}
在以上代碼有很詳細的注釋,在這里還是在簡單的提下:
RedisCacheConfig這里也可以不用繼承:CachingConfigurerSupport,也就是直接一個普通的Class就好了;這里主要我們之后要重新實現 key的生成策略,只要這里修改KeyGenerator,其它位置不用修改就生效了。普通使用普通類的方式的話,那么在使用@Cacheable的時候還需要指定KeyGenerator的名稱;這樣編碼的時候比較麻煩。
(6)編寫DemoInfo測試實體類;
編寫一個測試實體類:com.kfit.bean.DemoInfo:
package com.kfit.bean;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
/**
* 測試實體類,這個隨便;
* @author Angel(QQ:412887952)
* @version v.0.1
*/
@Entity
public class DemoInfo implements Serializable{
private static final long serialVersionUID = 1L;
@Id @GeneratedValue
private long id;
private String name;
private String pwd;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public StringgetName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd(){
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public StringtoString() {
return "DemoInfo [id=" + id + ",name=" + name + ", pwd=" + pwd + "]";
}
}
(7)編寫DemoInfoRepository持久化類;
DemoInfoRepository使用Spirng DataJPA實現:
com.kfit.repository.DemoInfoRepository:
package com.kfit.repository;
import org.springframework.data.repository.CrudRepository;
import com.kfit.bean.DemoInfo;
/**
* DemoInfo持久化類
* @author Angel(QQ:412887952)
* @version v.0.1
*/
public interfaceDemoInfoRepository extends CrudRepository<DemoInfo,Long> {
}
(8)編寫DemoInfoService類;
編寫DemoInfoService,這里有兩個技術方面,第一就是使用Spring @Cacheable注解方式和RedisTemplate對象進行操作,具體代碼如下:
com.kfit.service.DemoInfoService:
package com.kfit.service;
import com.kfit.bean.DemoInfo;
/**
* demoInfo 服務接口
* @author Angel(QQ:412887952)
* @version v.0.1
*/
public interface DemoInfoService{
public DemoInfofindById(long id);
public voiddeleteFromCache(long id);
void test();
}
com.kfit.service.impl.DemoInfoServiceImpl:
package com.kfit.service.impl;
import javax.annotation.Resource;
importorg.springframework.cache.annotation.CacheEvict;
importorg.springframework.cache.annotation.Cacheable;
importorg.springframework.data.redis.core.RedisTemplate;
importorg.springframework.data.redis.core.ValueOperations;
importorg.springframework.stereotype.Service;
import com.kfit.bean.DemoInfo;
importcom.kfit.repository.DemoInfoRepository;
import com.kfit.service.DemoInfoService;
/**
*
*DemoInfo數據處理類
*
* @author Angel(QQ:412887952)
* @version v.0.1
*/
@Service
public class DemoInfoServiceImpl implements DemoInfoService{
@Resource
privateDemoInfoRepository demoInfoRepository;
@Resource
privateRedisTemplate<String,String> redisTemplate;
@Override
public void test(){
ValueOperations<String,String>valueOperations = redisTemplate.opsForValue();
valueOperations.set("mykey4", "random1="+Math.random());
System.out.println(valueOperations.get("mykey4"));
}
//keyGenerator="myKeyGenerator"
@Cacheable(value="demoInfo") //緩存,這里沒有指定key.
@Override
public DemoInfofindById(long id) {
System.err.println("DemoInfoServiceImpl.findById()=========從數據庫中進行獲取的....id="+id);
return demoInfoRepository.findOne(id);
}
@CacheEvict(value="demoInfo")
@Override
public void deleteFromCache(long id) {
System.out.println("DemoInfoServiceImpl.delete().從緩存中刪除.");
}
}
(9)編寫DemoInfoController類;
package com.kfit.controller;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Controller;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.ResponseBody;
import com.kfit.bean.DemoInfo;
import com.kfit.service.DemoInfoService;
/**
* 測試類.
* @author Angel(QQ:412887952)
* @version v.0.1
*/
@Controller
public class DemoInfoController {
@Autowired
DemoInfoService demoInfoService;
@RequestMapping("/test")
public @ResponseBody String test(){
DemoInfo loaded = demoInfoService.findById(1);
System.out.println("loaded="+loaded);
DemoInfo cached = demoInfoService.findById(1);
System.out.println("cached="+cached);
loaded = demoInfoService.findById(2);
System.out.println("loaded2="+loaded);
return "ok";
}
@RequestMapping("/delete")
public @ResponseBody String delete(long id){
demoInfoService.deleteFromCache(id);
return "ok";
}
@RequestMapping("/test1")
public @ResponseBody String test1(){
demoInfoService.test();
System.out.println("DemoInfoController.test1()");
return "ok";
}
}
(10)測試代碼是否正常運行了
啟動應用程序,訪問地址:http://127.0.0.1:8080/test
查看控制台可以查看:
DemoInfoServiceImpl.findById()=========從數據庫中進行獲取的....id=1
loaded=DemoInfo [id=1, name=張三, pwd=123456]
cached=DemoInfo [id=1, name=張三, pwd=123456]
DemoInfoServiceImpl.findById()=========從數據庫中進行獲取的....id=2
loaded2=DemoInfo [id=2, name=張三, pwd=123456]
如果你看到以上的打印信息的話,那么說明緩存成功了。
訪問地址:http://127.0.0.1:8080/test1
random1=0.9985031320746356
DemoInfoController.test1()
二次訪問:http://127.0.0.1:8080/test
loaded=DemoInfo [id=1, name=張三, pwd=123456]
cached=DemoInfo [id=1, name=張三, pwd=123456]
loaded2=DemoInfo [id=2, name=張三, pwd=123456]
這時候所有的數據都是執行緩存的。
這時候執行刪除動作:http://127.0.0.1:8080/delete?id=1
然后在訪問:http://127.0.0.1:8080/test
DemoInfoServiceImpl.findById()=========從數據庫中進行獲取的....id=1
loaded=DemoInfo [id=1, name=張三, pwd=123456]
cached=DemoInfo [id=1, name=張三, pwd=123456]
loaded2=DemoInfo [id=2, name=張三, pwd=123456]
(11)自定義緩存key;
在com.kfit.config.RedisCacheConfig類中重寫CachingConfigurerSupport中的keyGenerator ,具體實現代碼如下:
/**
* 自定義key.
* 此方法將會根據類名+方法名+所有參數的值生成唯一的一個key,即使@Cacheable中的value屬性一樣,key也會不一樣。
*/
@Override
public KeyGeneratorkeyGenerator() {
System.out.println("RedisCacheConfig.keyGenerator()");
return new KeyGenerator(){
@Override
public Objectgenerate(Object o, Method method, Object... objects) {
// This willgenerate a unique key of the class name, the method name
//and allmethod parameters appended.
StringBuildersb = newStringBuilder();
sb.append(o.getClass().getName());
sb.append(method.getName());
for (Object obj : objects) {
sb.append(obj.toString());
}
System.out.println("keyGenerator=" + sb.toString());
return sb.toString();
}
};
}
這時候在redis的客戶端查看key的話還是序列化的肉眼看到就是亂碼了,那么我改變key的序列方式,這個很簡單,redis底層已經有具體的實現類了,我們只需要配置下:
//key序列化方式;(不然會出現亂碼;),但是如果方法上有Long等非String類型的話,會報類型轉換錯誤;
//所以在沒有自己定義key生成策略的時候,以下這個代碼建議不要這么寫,可以不配置或者自己實現ObjectRedisSerializer
//或者JdkSerializationRedisSerializer序列化方式;
RedisSerializer<String>redisSerializer = newStringRedisSerializer();//Long類型不可以會出現異常信息;
redisTemplate.setKeySerializer(redisSerializer);
redisTemplate.setHashKeySerializer(redisSerializer);
綜上以上分析:RedisCacheConfig類的方法調整為:
package com.kfit.config;
import java.lang.reflect.Method;
importorg.springframework.cache.CacheManager;
importorg.springframework.cache.annotation.CachingConfigurerSupport;
importorg.springframework.cache.annotation.EnableCaching;
importorg.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.data.redis.cache.RedisCacheManager;
importorg.springframework.data.redis.connection.RedisConnectionFactory;
importorg.springframework.data.redis.core.RedisTemplate;
importorg.springframework.data.redis.serializer.RedisSerializer;
importorg.springframework.data.redis.serializer.StringRedisSerializer;
/**
* redis 緩存配置;
*
* 注意:RedisCacheConfig這里也可以不用繼承 :CachingConfigurerSupport,也就是直接一個普通的Class就好了;
*
* 這里主要我們之后要重新實現 key的生成策略,只要這里修改KeyGenerator,其它位置不用修改就生效了。
*
* 普通使用普通類的方式的話,那么在使用@Cacheable的時候還需要指定KeyGenerator的名稱;這樣編碼的時候比較麻煩。
*
* @author Angel(QQ:412887952)
* @version v.0.1
*/
@Configuration
@EnableCaching //啟用緩存,這個注解很重要;
public class RedisCacheConfig extendsCachingConfigurerSupport {
/**
* 緩存管理器.
* @param redisTemplate
* @return
*/
@Bean
public CacheManagercacheManager(RedisTemplate<?,?> redisTemplate) {
CacheManagercacheManager = newRedisCacheManager(redisTemplate);
return cacheManager;
}
/**
* RedisTemplate緩存操作類,類似於jdbcTemplate的一個類;
*
* 雖然CacheManager也能獲取到Cache對象,但是操作起來沒有那么靈活;
*
* 這里在擴展下:RedisTemplate這個類不見得很好操作,我們可以在進行擴展一個我們
*
* 自己的緩存類,比如:RedisStorage類;
*
* @param factory : 通過Spring進行注入,參數在application.properties進行配置;
* @return
*/
@Bean
publicRedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String,String> redisTemplate = new RedisTemplate<String, String>();
redisTemplate.setConnectionFactory(factory);
//key序列化方式;(不然會出現亂碼;),但是如果方法上有Long等非String類型的話,會報類型轉換錯誤;
//所以在沒有自己定義key生成策略的時候,以下這個代碼建議不要這么寫,可以不配置或者自己實現ObjectRedisSerializer
//或者JdkSerializationRedisSerializer序列化方式;
RedisSerializer<String>redisSerializer = newStringRedisSerializer();//Long類型不可以會出現異常信息;
redisTemplate.setKeySerializer(redisSerializer);
redisTemplate.setHashKeySerializer(redisSerializer);
return redisTemplate;
}
/**
* 自定義key.
* 此方法將會根據類名+方法名+所有參數的值生成唯一的一個key,即使@Cacheable中的value屬性一樣,key也會不一樣。
*/
@Override
public KeyGeneratorkeyGenerator() {
System.out.println("RedisCacheConfig.keyGenerator()");
return new KeyGenerator(){
@Override
public Objectgenerate(Object o, Method method, Object... objects) {
// This willgenerate a unique key of the class name, the method name
//and allmethod parameters appended.
StringBuildersb = newStringBuilder();
sb.append(o.getClass().getName());
sb.append(method.getName());
for (Object obj : objects) {
sb.append(obj.toString());
}
System.out.println("keyGenerator=" + sb.toString());
return sb.toString();
}
};
}
}
這時候在訪問地址:http://127.0.0.1:8080/test
這時候看到的Key就是:com.kfit.service.impl.DemoInfoServiceImplfindById1
在控制台打印信息是:
(1)keyGenerator=com.kfit.service.impl.DemoInfoServiceImplfindById1
(2)DemoInfoServiceImpl.findById()=========從數據庫中進行獲取的....id=1
(3)keyGenerator=com.kfit.service.impl.DemoInfoServiceImplfindById1
(4)loaded=DemoInfo[id=1, name=張三, pwd=123456]
(5)keyGenerator=com.kfit.service.impl.DemoInfoServiceImplfindById1
(6)cached=DemoInfo[id=1, name=張三, pwd=123456]
(7)keyGenerator=com.kfit.service.impl.DemoInfoServiceImplfindById2
(8)keyGenerator=com.kfit.service.impl.DemoInfoServiceImplfindById2
(10)DemoInfoServiceImpl.findById()=========從數據庫中進行獲取的....id=2
(11)loaded2=DemoInfo[id=2, name=張三, pwd=123456]
其中@Cacheable,@CacheEvict下節進行簡單的介紹,這節的東西實在是太多了,到這里就打住吧,剩下的就需要靠你們自己進行擴展了。