Spring Boot集成Redis实现缓存机制(从零开始学Spring Boot)
本文章牵涉到的技术点比较多:springDataJPA、Redis、SpringMVC,SpirngCache,所以在看这篇文章的时候,需要对以上这些技术点有一定的了解或者也可以先看看这篇文章,针对文章中实际的技术点在进一步了解(注意,您需要自己下载RedisServer到您的本地,所以确保您本地的Redis可用,这里还使用了MySQL数据库,当然你也可以内存数据库进行测试)。这篇文章会提供对应的Eclipse代码示例,具体大体的分如下几个步骤:
(1)新建JavaMavenProject;
(2)在pom.xml中添加相应的依赖包;
(3)编写SpringBoot启动类;
(4)配置application.properties;
(5)编写RedisCacheConfig配置类;
(6)编写DemoInfo测试实体类;
(7)编写DemoInfoRepository持久化类;
(8)编写DemoInfoService类;
(9)编写DemoInfoController类;
(10)测试代码是否正常运行了
(11)自定义缓存key;
(1)新建JavaMavenProject;
这个步骤就不细说,新建一个spring-boot-redisJavamavenproject;
(2)在pom.xml中添加相应的依赖包;
在Maven中添加相应的依赖包,主要有:springboot父节点依赖;springbootweb支持;缓存服务spring-context-support;添加redis支持;JPA操作数据库;mysql数据库驱动,具体pom.xml文件如下:
4.0.0 com.kfit spring-boot-redis 0.0.1-SNAPSHOT jar spring-boot-redis http://maven.apache.org UTF-8 1.8 org.springframework.boot spring-boot-starter-parent 1.3.3.RELEASE junit junit test org.springframework.boot spring-boot-starter-web org.springframework spring-context-support org.springframework.boot spring-boot-starter-redis org.springframework.boot spring-boot-starter-data-jpa mysql mysql-connector-java org.springframework.boot spring-boot-starter-test test
上面是完整的pom.xml文件,每个里面都进行了简单的注释。
(3)编写SpringBoot启动类(com.kfit.App);
packagecom.kfit;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
/**
*SpringBoot启动类;
*
*@authorAngel(QQ:412887952)
*@versionv.0.1
*/
@SpringBootApplication
publicclassApp{
/**
*-javaagent:.\lib\springloaded-1.2.4.RELEASE.jar-noverify
*@paramargs
*/
publicstaticvoidmain(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基本配置; ######################################################## #databasename spring.redis.database=0 #serverhost1 spring.redis.host=127.0.0.1 #serverpassword #spring.redis.password= #connectionport spring.redis.port=6379 #poolsettings... spring.redis.pool.max-idle=8 spring.redis.pool.min-idle=0 spring.redis.pool.max-active=8 spring.redis.pool.max-wait=-1 #nameofRedisserver #spring.redis.sentinel.master= #comma-separatedlistofhost:portpairs #spring.redis.sentinel.nodes= ######################################################## ###JavaPersistenceApi自动进行建表 ######################################################## #SpecifytheDBMS spring.jpa.database=MYSQL #Showornotlogforeachsqlquery spring.jpa.show-sql=true #hibernateddlauto(create,create-drop,update) spring.jpa.hibernate.ddl-auto=update #Namingstrategy spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy #strippedbeforeaddingthemtotheentitymanager) spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
(5)编写RedisCacheConfig配置类;
缓存主要有几个要实现的类:其一就是CacheManager缓存管理器;其二就是具体操作实现类;其三就是CacheManager工厂类(这个可以使用配置文件配置的进行注入,也可以通过编码的方式进行实现);其四就是缓存key生产策略(当然Spring自带生成策略,但是在Redis客户端进行查看的话是系列化的key,对于我们肉眼来说就是感觉是乱码了,这里我们先使用自带的缓存策略)。
com.kfit.config/RedisCacheConfig:
packagecom.kfit.config;
importorg.springframework.cache.CacheManager;
importorg.springframework.cache.annotation.CachingConfigurerSupport;
importorg.springframework.cache.annotation.EnableCaching;
importorg.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;
/**
*redis缓存配置;
*
*注意:RedisCacheConfig这里也可以不用继承:CachingConfigurerSupport,也就是直接一个普通的Class就好了;
*
*这里主要我们之后要重新实现key的生成策略,只要这里修改KeyGenerator,其它位置不用修改就生效了。
*
*普通使用普通类的方式的话,那么在使用@Cacheable的时候还需要指定KeyGenerator的名称;这样编码的时候比较麻烦。
*
*@authorAngel(QQ:412887952)
*@versionv.0.1
*/
@Configuration
@EnableCaching//启用缓存,这个注解很重要;
publicclassRedisCacheConfigextendsCachingConfigurerSupport{
/**
*缓存管理器.
*@paramredisTemplate
*@return
*/
@Bean
publicCacheManagercacheManager(RedisTemplate,?>redisTemplate){
CacheManagercacheManager=newRedisCacheManager(redisTemplate);
returncacheManager;
}
/**
*redis模板操作类,类似于jdbcTemplate的一个类;
*
*虽然CacheManager也能获取到Cache对象,但是操作起来没有那么灵活;
*
*这里在扩展下:RedisTemplate这个类不见得很好操作,我们可以在进行扩展一个我们
*
*自己的缓存类,比如:RedisStorage类;
*
*@paramfactory:通过Spring进行注入,参数在application.properties进行配置;
*@return
*/
@Bean
publicRedisTemplateredisTemplate(RedisConnectionFactoryfactory){
RedisTemplateredisTemplate=newRedisTemplate();
redisTemplate.setConnectionFactory(factory);
//key序列化方式;(不然会出现乱码;),但是如果方法上有Long等非String类型的话,会报类型转换错误;
//所以在没有自己定义key生成策略的时候,以下这个代码建议不要这么写,可以不配置或者自己实现ObjectRedisSerializer
//或者JdkSerializationRedisSerializer序列化方式;
//RedisSerializerredisSerializer=newStringRedisSerializer();//Long类型不可以会出现异常信息;
//redisTemplate.setKeySerializer(redisSerializer);
//redisTemplate.setHashKeySerializer(redisSerializer);
returnredisTemplate;
}
}
在以上代码有很详细的注释,在这里还是在简单的提下:
RedisCacheConfig这里也可以不用继承:CachingConfigurerSupport,也就是直接一个普通的Class就好了;这里主要我们之后要重新实现key的生成策略,只要这里修改KeyGenerator,其它位置不用修改就生效了。普通使用普通类的方式的话,那么在使用@Cacheable的时候还需要指定KeyGenerator的名称;这样编码的时候比较麻烦。
(6)编写DemoInfo测试实体类;
编写一个测试实体类:com.kfit.bean.DemoInfo:
packagecom.kfit.bean;
importjava.io.Serializable;
importjavax.persistence.Entity;
importjavax.persistence.GeneratedValue;
importjavax.persistence.Id;
/**
*测试实体类,这个随便;
*@authorAngel(QQ:412887952)
*@versionv.0.1
*/
@Entity
publicclassDemoInfoimplementsSerializable{
privatestaticfinallongserialVersionUID=1L;
@Id@GeneratedValue
privatelongid;
privateStringname;
privateStringpwd;
publiclonggetId(){
returnid;
}
publicvoidsetId(longid){
this.id=id;
}
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
publicStringgetPwd(){
returnpwd;
}
publicvoidsetPwd(Stringpwd){
this.pwd=pwd;
}
@Override
publicStringtoString(){
return"DemoInfo[id="+id+",name="+name+",pwd="+pwd+"]";
}
}
(7)编写DemoInfoRepository持久化类;
DemoInfoRepository使用SpirngDataJPA实现:
com.kfit.repository.DemoInfoRepository: packagecom.kfit.repository; importorg.springframework.data.repository.CrudRepository; importcom.kfit.bean.DemoInfo; /** *DemoInfo持久化类 *@authorAngel(QQ:412887952) *@versionv.0.1 */ publicinterfaceDemoInfoRepositoryextendsCrudRepository{ }
(8)编写DemoInfoService类;
编写DemoInfoService,这里有两个技术方面,第一就是使用Spring@Cacheable注解方式和RedisTemplate对象进行操作,具体代码如下:
com.kfit.service.DemoInfoService:
packagecom.kfit.service;
importcom.kfit.bean.DemoInfo;
/**
*demoInfo服务接口
*@authorAngel(QQ:412887952)
*@versionv.0.1
*/
publicinterfaceDemoInfoService{
publicDemoInfofindById(longid);
publicvoiddeleteFromCache(longid);
voidtest();
}
com.kfit.service.impl.DemoInfoServiceImpl:
packagecom.kfit.service.impl;
importjavax.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;
importcom.kfit.bean.DemoInfo;
importcom.kfit.repository.DemoInfoRepository;
importcom.kfit.service.DemoInfoService;
/**
*
*DemoInfo数据处理类
*
*@authorAngel(QQ:412887952)
*@versionv.0.1
*/
@Service
publicclassDemoInfoServiceImplimplementsDemoInfoService{
@Resource
privateDemoInfoRepositorydemoInfoRepository;
@Resource
privateRedisTemplateredisTemplate;
@Override
publicvoidtest(){
ValueOperationsvalueOperations=redisTemplate.opsForValue();
valueOperations.set("mykey4","random1="+Math.random());
System.out.println(valueOperations.get("mykey4"));
}
//keyGenerator="myKeyGenerator"
@Cacheable(value="demoInfo")//缓存,这里没有指定key.
@Override
publicDemoInfofindById(longid){
System.err.println("DemoInfoServiceImpl.findById()=========从数据库中进行获取的....id="+id);
returndemoInfoRepository.findOne(id);
}
@CacheEvict(value="demoInfo")
@Override
publicvoiddeleteFromCache(longid){
System.out.println("DemoInfoServiceImpl.delete().从缓存中删除.");
}
}
(9)编写DemoInfoController类;
packagecom.kfit.controller;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Controller;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.ResponseBody;
importcom.kfit.bean.DemoInfo;
importcom.kfit.service.DemoInfoService;
/**
*测试类.
*@authorAngel(QQ:412887952)
*@versionv.0.1
*/
@Controller
publicclassDemoInfoController{
@Autowired
DemoInfoServicedemoInfoService;
@RequestMapping("/test")
public@ResponseBodyStringtest(){
DemoInfoloaded=demoInfoService.findById(1);
System.out.println("loaded="+loaded);
DemoInfocached=demoInfoService.findById(1);
System.out.println("cached="+cached);
loaded=demoInfoService.findById(2);
System.out.println("loaded2="+loaded);
return"ok";
}
@RequestMapping("/delete")
public@ResponseBodyStringdelete(longid){
demoInfoService.deleteFromCache(id);
return"ok";
}
@RequestMapping("/test1")
public@ResponseBodyStringtest1(){
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
publicKeyGeneratorkeyGenerator(){
System.out.println("RedisCacheConfig.keyGenerator()");
returnnewKeyGenerator(){
@Override
publicObjectgenerate(Objecto,Methodmethod,Object...objects){
//Thiswillgenerateauniquekeyoftheclassname,themethodname
//andallmethodparametersappended.
StringBuildersb=newStringBuilder();
sb.append(o.getClass().getName());
sb.append(method.getName());
for(Objectobj:objects){
sb.append(obj.toString());
}
System.out.println("keyGenerator="+sb.toString());
returnsb.toString();
}
};
}
这时候在redis的客户端查看key的话还是序列化的肉眼看到就是乱码了,那么我改变key的序列方式,这个很简单,redis底层已经有具体的实现类了,我们只需要配置下:
//key序列化方式;(不然会出现乱码;),但是如果方法上有Long等非String类型的话,会报类型转换错误; //所以在没有自己定义key生成策略的时候,以下这个代码建议不要这么写,可以不配置或者自己实现ObjectRedisSerializer //或者JdkSerializationRedisSerializer序列化方式; RedisSerializerredisSerializer=newStringRedisSerializer();//Long类型不可以会出现异常信息; redisTemplate.setKeySerializer(redisSerializer); redisTemplate.setHashKeySerializer(redisSerializer);
综上以上分析:RedisCacheConfig类的方法调整为:
packagecom.kfit.config;
importjava.lang.reflect.Method;
importorg.springframework.cache.CacheManager;
importorg.springframework.cache.annotation.CachingConfigurerSupport;
importorg.springframework.cache.annotation.EnableCaching;
importorg.springframework.cache.interceptor.KeyGenerator;
importorg.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的名称;这样编码的时候比较麻烦。
*
*@authorAngel(QQ:412887952)
*@versionv.0.1
*/
@Configuration
@EnableCaching//启用缓存,这个注解很重要;
publicclassRedisCacheConfigextendsCachingConfigurerSupport{
/**
*缓存管理器.
*@paramredisTemplate
*@return
*/
@Bean
publicCacheManagercacheManager(RedisTemplate,?>redisTemplate){
CacheManagercacheManager=newRedisCacheManager(redisTemplate);
returncacheManager;
}
/**
*RedisTemplate缓存操作类,类似于jdbcTemplate的一个类;
*
*虽然CacheManager也能获取到Cache对象,但是操作起来没有那么灵活;
*
*这里在扩展下:RedisTemplate这个类不见得很好操作,我们可以在进行扩展一个我们
*
*自己的缓存类,比如:RedisStorage类;
*
*@paramfactory:通过Spring进行注入,参数在application.properties进行配置;
*@return
*/
@Bean
publicRedisTemplateredisTemplate(RedisConnectionFactoryfactory){
RedisTemplateredisTemplate=newRedisTemplate();
redisTemplate.setConnectionFactory(factory);
//key序列化方式;(不然会出现乱码;),但是如果方法上有Long等非String类型的话,会报类型转换错误;
//所以在没有自己定义key生成策略的时候,以下这个代码建议不要这么写,可以不配置或者自己实现ObjectRedisSerializer
//或者JdkSerializationRedisSerializer序列化方式;
RedisSerializerredisSerializer=newStringRedisSerializer();//Long类型不可以会出现异常信息;
redisTemplate.setKeySerializer(redisSerializer);
redisTemplate.setHashKeySerializer(redisSerializer);
returnredisTemplate;
}
/**
*自定义key.
*此方法将会根据类名+方法名+所有参数的值生成唯一的一个key,即使@Cacheable中的value属性一样,key也会不一样。
*/
@Override
publicKeyGeneratorkeyGenerator(){
System.out.println("RedisCacheConfig.keyGenerator()");
returnnewKeyGenerator(){
@Override
publicObjectgenerate(Objecto,Methodmethod,Object...objects){
//Thiswillgenerateauniquekeyoftheclassname,themethodname
//andallmethodparametersappended.
StringBuildersb=newStringBuilder();
sb.append(o.getClass().getName());
sb.append(method.getName());
for(Objectobj:objects){
sb.append(obj.toString());
}
System.out.println("keyGenerator="+sb.toString());
returnsb.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下节进行简单的介绍,这节的东西实在是太多了,到这里就打住吧,剩下的就需要靠你们自己进行扩展了。
以上所述是小编给大家介绍的SpringBoot集成Redis实现缓存机制(从零开始学SpringBoot),希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!