在Spring Boot中添加spring-boot-starter-data-redis依赖:

        <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

在application.properties中指定redis服务器IP、端口和密码、连接数等:

# Redis服务器地址
spring.redis.host=127.0.0.1
# Redis服务器连接端口 使用默认端口6379可以省略配置
#spring.redis.port=6379
# Redis服务器连接密码(默认为空)
#spring.redis.password=
# 连接池最大连接数(如果配置<=0,则没有限制 )
spring.redis.jedis.pool.max-active=8

使用StringRedisTemplate 和RedisTemplate

StringRedisTemplate是Spring Boot内置的操作Redis的API实现类,另外还有一个API实现类是RedisTemplate。StringRedisTemplate的API假定所有的数据类型化都是字符类型,即key和value都是字符串类型,对于常见额SpringBoot应用系统,使用字符串操作也已经足够了,而且能方便的通过客户端管理工具管理。StringRedisTemplate继承RedisTemplate,与RedisTemplate不同的是重新设置了序列化策略,使用StringRedisSerialier类来序列化key-value,包括List、Hash、Set等数据结构。

 @RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootCacheApplicationTests { @Autowired
StringRedisTemplate stringRedisTemplate; //操作 k-v 字符串 @Autowired
   RedisTemplate redisTemplate; //k- v 都是对象 /**
* redis 常见
* String(字符串) List(列表) Set(集合) Hash(散列) ZSet(有序集合)
*/ @Test
public void test1() {
stringRedisTemplate.opsForValue().append("StringKey", "字符串数值");
String value = stringRedisTemplate.opsForValue().get("StringKey");
System.out.println(value);
}
  @Test
  public void test2() { Product product = productMapper.getProductById(4L);
redisTemplate.opsForValue().set("produxtid4",product); }
}

spring-boot-autoconfigure-2.0.4.RELEASE.jar包中RedisAutoConfiguration.java已经自动声明了两个redis操作bean:

RedisAutoConfiguration.java实现代码:

因此我们只要在使用的地方注入即可:

@Autowired
StringRedisTemplate stringRedisTemplate; //操作 k-v 字符串
@Autowired
RedisTemplate redisTemplate; //k- v 都是对象

StringRedisTemplate 提供opsForValue用来操作key-value,如上面的示例,另外还提供了一系列opsForHash()、opsForList()、opsForSet()、opsForZSet()等方法用来操作不同结构类型的数据。

运行上面的测试方法,查看redis客户端:

可以发现,出现了一些无法识别的字符,查看RedisTemplate源码可这个是由于默认使用了JDK的序列化机制,而StringRedisTemplate没有出乱码是因为它修改了序列化器

StringRedisTemplate实现:

 public class StringRedisTemplate extends RedisTemplate<String, String> {

    /**
* Constructs a new <code>StringRedisTemplate</code> instance. {@link #setConnectionFactory(RedisConnectionFactory)}
* and {@link #afterPropertiesSet()} still need to be called.
*/
public StringRedisTemplate() {
RedisSerializer<String> stringSerializer = new StringRedisSerializer();
setKeySerializer(stringSerializer);
setValueSerializer(stringSerializer);
setHashKeySerializer(stringSerializer);
setHashValueSerializer(stringSerializer);
} /**
* Constructs a new <code>StringRedisTemplate</code> instance ready to be used.
*
* @param connectionFactory connection factory for creating new connections
*/
public StringRedisTemplate(RedisConnectionFactory connectionFactory) {
this();
setConnectionFactory(connectionFactory);
afterPropertiesSet();
} protected RedisConnection preProcessConnection(RedisConnection connection, boolean existingConnection) {
return new DefaultStringRedisConnection(connection);
}
}

RedisTemplate实现,截取默认序列化器相关源码:

 @Override
public void afterPropertiesSet() { super.afterPropertiesSet(); boolean defaultUsed = false; if (defaultSerializer == null) {
//默认序列化器使用JdkSerializationRedisSerializer
defaultSerializer = new JdkSerializationRedisSerializer(
classLoader != null ? classLoader : this.getClass().getClassLoader());
} if (enableDefaultSerializer) { if (keySerializer == null) {
keySerializer = defaultSerializer;
defaultUsed = true;
}
if (valueSerializer == null) {
valueSerializer = defaultSerializer;
defaultUsed = true;
}
if (hashKeySerializer == null) {
hashKeySerializer = defaultSerializer;
defaultUsed = true;
}
if (hashValueSerializer == null) {
hashValueSerializer = defaultSerializer;
defaultUsed = true;
}
} if (enableDefaultSerializer && defaultUsed) {
Assert.notNull(defaultSerializer, "default serializer null and not all serializers initialized");
} if (scriptExecutor == null) {
this.scriptExecutor = new DefaultScriptExecutor<>(this);
} initialized = true;
}

既然RedisTemplate的默认序列化器不是很方便在redis管理工具中查看,我们可以自己定义一个RedisTemplate实例,修改默认的序列化器。

实现方式如下,定义一个配置类,重新注入一个RedisTemplate操作bean:

 @Configuration
public class MyRedisConfig {    @Bean(name = "redisTemplate")
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){ RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
     //参照StringRedisTemplate内部实现指定序列化器
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(keySerializer());
redisTemplate.setHashKeySerializer(keySerializer());
redisTemplate.setValueSerializer(valueSerializer());
redisTemplate.setHashValueSerializer(valueSerializer()); return redisTemplate;
} private RedisSerializer<String> keySerializer() {
return new StringRedisSerializer();
}
  //使用Jackson序列化器
private RedisSerializer<Object> valueSerializer() {
return new GenericJackson2JsonRedisSerializer();
}
}

重新运行上面的测试代码,可以发现redis客户端中已经可以正常的显示json格式数据了。

SpringBoot集成redis + spring cache

Spring Cache集成redis的运行原理:

Spring缓存抽象模块通过CacheManager来创建、管理实际缓存组件,当SpringBoot应用程序引入spring-boot-starter-data-redi依赖后吗,容器中将注册的是CacheManager实例RedisCacheManager对象,RedisCacheManager来负责创建RedisCache作为缓存管理组件,由RedisCache操作redis服务器实现缓存数据操作。实际测试发现默认注入的RedisCacheManager操作缓存用的是RedisTemplate<Object, Object>,因此我们需要自定义cacheManager,替换掉默认的序列化器。

实现代码:

添加mybatis和redis依赖:

<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

添加mapper映射:

 @Mapper
public interface ProductMapper {
@Select("select * from tb_product where product_id=#{id}")
Product getProductById(Long id); @Update("update tb_product set product_name=#{productName},product_desc=#{productDesc} WHERE product_id=#{productId}")
int updateProduct(Product product); @Delete("delete from tb_product where product_id=#{id}")
void deleteProductById(Long id); @Select("select * from tb_product where product_name=#{productName}")
Product getProductByName(String productName);
}

Service:

 package com.sl.cache.service;
import com.sl.cache.entity.Product;
import com.sl.cache.mapper.ProductMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service; @Service
@CacheConfig(cacheNames = "product")
public class ProductService {
@Autowired
private ProductMapper productMapper; @Cacheable(cacheNames = "product1",key = "#root.methodName+'['+#id+']'")
//@Cacheable(cacheNames = {"product1","product2"})// 默认key为参数,多个参数SimpleKey [arg1,arg2]
//@Cacheable(cacheNames = "product",key = "#root.methodName+'['+#id+']'")
//@Cacheable(cacheNames = "product",keyGenerator = "myKeyGenerator")
//@Cacheable(cacheNames = "product",key = "#root.methodName+'['+#id+']'",condition="#a0>10",unless = "#a0==11") //或者condition="#id>10")
public Product getProductById(Long id){
Product product =productMapper.getProductById(id);
System.out.println(product);
return product;
} @CachePut(value="product",key = "#result.productId",condition = "#result!=null")
public Product updateProduct(Product product){
int count = productMapper.updateProduct(product);
System.out.println("影响行数:"+count);
if(count>0){
return product;
}else{
return null;
}
} //@CacheEvict(value="product",key="#id")
//@CacheEvict(value="product",allEntries = true) //清楚所有缓存
@CacheEvict(value="product",allEntries = true,beforeInvocation = true) //清楚所有缓存
public boolean deleteProductById(Long id) {
productMapper.deleteProductById(id);
return true;
} //含有CachePut注解,所以执行这个方法时一定会查询数据库,及时有cacheable注解
@Caching(
cacheable = {@Cacheable(value="product",key="#productName")},
put = {
@CachePut(value="product",key="#result.productId"),
@CachePut(value="product",key="#result.productName")
}
)
public Product getProductByName(String productName){ Product product =productMapper.getProductByName(productName); return product;
}
}

Controller:

package com.sl.cache.controller;
import com.sl.cache.entity.Product;
import com.sl.cache.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; @RestController
public class ProductController { @Autowired
private ProductService productService; @GetMapping("/product/{id}")
public Product getProduct(@PathVariable("id") Long id) { Product product = productService.getProductById(id);
return product;
} //prooduct?productid=1&productName= &
@GetMapping("/product")
public Product updateProduct(Product product) {
productService.updateProduct(product);
return product;
} @GetMapping("/delproduct")
public String delProduct(@RequestParam(value="id") Long id) { productService.deleteProductById(id);
return "ok";
} @GetMapping("/product/name/{productName}")
public Product getEmpByLastName(@PathVariable("productName") String productName){
return productService.getProductByName(productName);
}
}

自定义cacheManager实现:

 package com.sl.cache.config;
import com.sl.cache.entity.Product;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cache.CacheManager;
import org.springframework.cache.config.CacheManagementConfigUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer; import java.net.UnknownHostException;
import java.time.Duration; @Configuration
public class MyRedisConfig { @Bean(name = "redisTemplate")
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){ RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(keySerializer());
redisTemplate.setHashKeySerializer(keySerializer());
redisTemplate.setValueSerializer(valueSerializer());
redisTemplate.setHashValueSerializer(valueSerializer());
return redisTemplate;
} @Primary
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory){
//缓存配置对象
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig(); redisCacheConfiguration = redisCacheConfiguration.entryTtl(Duration.ofMinutes(30L)) //设置缓存的默认超时时间:30分钟
.disableCachingNullValues() //如果是空值,不缓存
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer())) //设置key序列化器
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer((valueSerializer()))); //设置value序列化器 return RedisCacheManager
.builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory))
.cacheDefaults(redisCacheConfiguration).build();
}
private RedisSerializer<String> keySerializer() {
return new StringRedisSerializer();
} private RedisSerializer<Object> valueSerializer() {
return new GenericJackson2JsonRedisSerializer();
}
}

启用缓存,添加mybatis Mapper映射扫描:

 @MapperScan("com.sl.cache.mapper")
@SpringBootApplication
@EnableCaching
public class SpringbootCacheApplication { public static void main(String[] args) {
SpringApplication.run(SpringbootCacheApplication.class, args); }
}

Spring Boot(八)集成Spring Cache 和 Redis的更多相关文章

  1. Spring Boot中集成Spring Security 专题

    check to see if spring security is applied that the appropriate resources are permitted: @Configurat ...

  2. spring-boot-starter-security Spring Boot中集成Spring Security

    spring security是springboot支持的权限控制系统. security.basic.authorize-mode 要使用权限控制模式. security.basic.enabled ...

  3. Spring Boot 中集成 Redis 作为数据缓存

    只添加注解:@Cacheable,不配置key时,redis 中默认存的 key 是:users::SimpleKey [](1.redis-cli 中,通过命令:keys * 查看:2.key:缓存 ...

  4. Spring Boot(八):RabbitMQ详解

    Spring Boot(八):RabbitMQ详解 RabbitMQ 即一个消息队列,主要是用来实现应用程序的异步和解耦,同时也能起到消息缓冲,消息分发的作用. 消息中间件在互联网公司的使用中越来越多 ...

  5. Spring Boot快速集成kaptcha生成验证码

    Kaptcha是一个非常实用的验证码生成工具,可以通过配置生成多样化的验证码,以图片的形式显示,从而无法进行复制粘贴:下面将详细介绍下Spring Boot快速集成kaptcha生成验证码的过程. 本 ...

  6. Spring Boot日志集成实战

    Spring Boot日志框架 Spring Boot支持Java Util Logging,Log4j2,Lockback作为日志框架,如果你使用starters启动器,Spring Boot将使用 ...

  7. Spring Boot日志集成

    Spring Boot日志框架 Spring Boot支持Java Util Logging,Log4j2,Lockback作为日志框架,如果你使用starters启动器,Spring Boot将使用 ...

  8. Spring Boot:集成Druid数据源

    综合概述 数据库连接池负责分配.管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个:释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据 ...

  9. shiro 和 spring boot 的集成

    1 添加依赖 使用 shiro-spring-boot-web-starter 在 spring boot 中集成 shiro 只需要再添加一个依赖 <dependency> <gr ...

  10. [转帖]spring boot项目集成jacoco

    小试牛刀:spring boot项目集成jacoco 2019-03-28 20:14:36 zyq23333 阅读数 509   版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议, ...

随机推荐

  1. Some cool FireMonkey multi-device components

    http://blogs.embarcadero.com/davidi/2014/01/16/43281 There are many available Delphi and C++Builder ...

  2. Oracle——系统数据字典常用命令(查看表所属空间层目录等)

    发生背景: 项目前后台交互对接时候,经常存在对底层表蒙圈情况尤其是oracle数据库,所在层级不同会导致操作对象直接的改变,从而发生意向不到的事情:很多时候需要了解我们所操作对象所处的层级等相关信息, ...

  3. golang 项目实战简明指南

    原文地址 开发环境搭建 golang 的开发环境搭建比较简单,由于是编译型语言,写好 golang 源码后,只需要执行 go build 就能将源码编译成对应平台(本文中默认为 linux)上的可执行 ...

  4. 利用“海底捞算法”在MongoDB中优雅地存储一棵树

    目前常见的树形结构数据库存储方案有以下四种,但是在处理无限深度.海量数据的树结构时,都存在一些问题: 1)Adjacency List(邻接表):每个节点仅记录父节点主键.优点是简单,缺点是访问子树需 ...

  5. 20155322 2017-2018-1 《信息安全系统设计》第五周 MyBash实现

    #20155322 2017-2018-1<信息安全系统设计>第五周 MyBash实现 [博客目录] 实现要求 相关知识 bash fork exec wait 相关问题 fork返回两次 ...

  6. 20155322 2016-2017-2 《Java程序设计》实验一 Java开发环境的熟悉(macOS + Eclipse)

    20155322 2016-2017-2 <Java程序设计>实验一 Java开发环境的熟悉(macOS + Eclipse) 实验目的与内容 熟悉命令行开发环境. 使用vim等文本编译器 ...

  7. 20155322 2016-2017-2 《Java程序设计》 第一周学习总结

    20155322 2016-2017-2 <Java程序设计> 第一周学习总结 教材学习内容总结 本周学习内容的主要是: 一.浏览教材,根据自己的理解每章提出一个问题. 在浏览教材后,我提 ...

  8. 【转】odoo学习之:开发字段解析

    odoo新API中,字段类型不变,继承改变 1.旧的API定义模型: from openerp.osv import osv,fields class oldmodel(osv.osv): #模型名称 ...

  9. [2016北京集训试题8]连在一起的幻想乡[dp+无向图计数]

    Description Solution 本博客参考yww大佬的博客,为了加深理解我就自己再写一遍啦. 以下的“无向图”均无重边无自环. 定义f0[n]为n个点构成的无向图个数,f1[n]为n个点构成 ...

  10. windows下安装,配置redis以及可视化客户端redisClient的安装及基本使用

    一. Window 下安装 下载地址:https://github.com/MSOpenTech/redis/releases. Redis 支持 32 位和 64 位.这个需要根据你系统平台的实际情 ...