Spring Boot web开发(九) 整合Redis实现缓存

12 篇文章 0 订阅
8 篇文章 0 订阅

目录

1. 缓存RedisTemplate

1.1 引入redis相关依赖

1.2 RedisTemplate操作Reids

2. 序列化机制

3. 自定义CacheManager

3.1 springboot 1.x自定义CacheManger

3.2 springboot 2.x自定义CacheManger


1. 缓存RedisTemplate

在我们没有配置其他缓存中间件的时候,默认使用的是ConcurrentMapCacheManager,ConcurrentMapCacheManager可以获取和创建ConcurrentMapCache类型的缓存组件,将数据保存在ConcurrentMap中。

而在开发的时候,大多数时候都要使用到缓存中间件,比如redis、ehcache等。本节就整合了redis,来实现缓存功能。

对于redis的基本操作,我前面已经做了一些基础介绍和使用方法的介绍:

参考链接:https://blog.csdn.net/chen_hao_181/article/category/9452823

本节还是采用以前的项目。

1.1 引入redis相关依赖

在pom文件中添加如下依赖:

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

然后再配置文件中(我使用的是yml文件)添加一个redis的主机ip,我使用的docker安装redis,你如果是本机安装就写localhost。

这样就成功引入了redis,接下来就可以使用redis了,redis和jdbc相似,可以使用RedisTemplate和StringRedisTemplate来操作redis,RedisTemplate用于key和value都是对象的时候,StringRedisTemplate用于操作String类型的数据。

1.2 RedisTemplate操作Reids

RedisTemplate和StringRedisTemplate都有一些相似的常用方法(StringRedisTemplate继承了RedisTemplate),如下所示:

    public ListOperations<K, V> opsForList() {

		if (listOps == null) {
			listOps = new DefaultListOperations<>(this);
		}
		return listOps;
	}

	public SetOperations<K, V> opsForSet() {

		if (setOps == null) {
			setOps = new DefaultSetOperations<>(this);
		}
		return setOps;
	}

	public ValueOperations<K, V> opsForValue() {

		if (valueOps == null) {
			valueOps = new DefaultValueOperations<>(this);
		}
		return valueOps;
	}

	public ZSetOperations<K, V> opsForZSet() {

		if (zSetOps == null) {
			zSetOps = new DefaultZSetOperations<>(this);
		}
		return zSetOps;
	}

	public <HK, HV> HashOperations<K, HK, HV> opsForHash() {
		return new DefaultHashOperations<>(this);
	}

	
	public HyperLogLogOperations<K, V> opsForHyperLogLog() {

		if (hllOps == null) {
			hllOps = new DefaultHyperLogLogOperations<>(this);
		}
		return hllOps;
	}

RedisTemplate和StirngRedisTemplate就能利用这些方法对redis进行操作。下面来做个例子

在test测试类中添加一个方法,我们向redis中添加一些字符串。

package com.chtw.springboot02;

import com.chtw.config.Hello;
import com.chtw.entity.User;
import com.chtw.service.HelloService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

import javax.sql.DataSource;
import java.sql.SQLException;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBoot02ApplicationTests {

	@Autowired
	DataSource dataSource;

	@Autowired
	HelloService helloService;

	@Autowired
	StringRedisTemplate stringRedisTemplate;

	@Autowired
	RedisTemplate redisTemplate;

	@Test
	public void redisTemplatetest() {
		stringRedisTemplate.opsForValue().append("message","hello world");
	}

	@Test
	public void sys() throws SQLException {
		System.out.println(dataSource.getClass());
		System.out.println(dataSource.getConnection());
	}


}

运行redisTemplatetest方法,再到redis里面去看:

就添加成功了,操作简单。下面我们在存放一个对象进去,你会发现它不是以json的新式存放的,redis的默认序列化机制没有将对象转化为json对象存放。redis默认的序列化机制是:jdk的序列化机制。

将方法改为如下后,重新运行测试方法:

	@Test
	public void redisTemplatetest() {
		User user = helloService.getUserById(1);
		redisTemplate.opsForList().leftPush("user",user);
		//stringRedisTemplate.opsForValue().append("message","hello world");
	}

在运行的过程中可能或出现如下错误:

这是因为我们的User对象不能被序列化,我们只需要在User实现Serializable:

然后再运行测试方法就可以了,运行结束后在到redis中看:

在实际开发工作中我们还是习惯将结果以json的形式将对象存储起来,下来具体看看序列化机制。

2. 序列化机制

在RedisAutoConfiguration中,给我们容器中添加了一个RedisTemplate,而在RedisTemplate中,有一个enableDefaultSerializer属性,它就是用来指定默认的序列化机制的。上面也看到默认使用的是JdkSerializationRedisSerializer这个序列化规则。

为了能够将对象序列化成json对象,我们也可以向容器中添加我们自己的序列化规则,写一个配置类,在里面添加我们自己的序列化规则就好了。

package com.chtw.config;

import com.chtw.entity.User;
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.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.*;

import java.net.UnknownHostException;
import java.time.Duration;

@Configuration
public class MyRedisConfig {

    @Bean
    public RedisTemplate<Object, User> userRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, User> template = new RedisTemplate<Object, User>();
        template.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer<User> ser = new Jackson2JsonRedisSerializer<User>(User.class);
        template.setDefaultSerializer(ser);
        return template;
    }

}

在测试类中添加如下方法:

	@Autowired
	RedisTemplate<Object, User> userRedisTemplate;
	
	@Test
	public void userRedisTemplatetest() {
		User user = helloService.getUserById(1);
		userRedisTemplate.opsForValue().set("user",user);
		//stringRedisTemplate.opsForValue().append("message","hello world");
	}

然后我们在去运行测试方法userRedisTemplatetest()这个时候就以json的形式保存了:

 

3. 自定义CacheManager

先再写一个实体类和相关查询方法:

JavaBean,People1类:

package com.chtw.entity;

/**
 * @author CHTW
 * @date 2019-11-05-16:06
 */
public class People1 implements Serializable{

    private int id;
    private String peoplename;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getPeoplename() {
        return peoplename;
    }

    public void setPeoplename(String peoplename) {
        this.peoplename = peoplename;
    }
}
    //controller层
    @ResponseBody
    @GetMapping("/getpeid")
    public People1 getpeById(int id){
        return helloService.getPeopleById(id);
    }
    //service层
    @Cacheable(value = "people",key="#id")
    public People1 getPeopleById(int id){
        People1 pList = peopleMapper.getPeopleById(id);
        if(pList!=null) {
            return pList;
        }else{
            return new People1();
        }
    }
    //dao层
    @Select("select * from people where id=#{id}")
    public People1 getPeopleById(int id);

新建一个people数据表:

3.1 springboot 1.x自定义CacheManger

原理:引入了redis的starter,cacheManager变为 RedisCacheManager;
默认创建的 RedisCacheManager 操作redis的时候使用的是 RedisTemplate<Object, Object>
RedisTemplate<Object, Object> 是 默认使用jdk的序列化机制:JdkSerializationRedisSerializer。

所以我们要指定我们的序列化规则:Jackson2JsonRedisSerializer。

Spring Boot 底层创建RedisCacheManager的源码是

那么我也可以参照源码来自定义我们的CacheManager:

package com.chtw.config;

import com.chtw.entity.User;
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.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.*;

import java.net.UnknownHostException;
import java.time.Duration;

@Configuration
public class MyRedisConfig {

    @Bean
    public RedisTemplate<Object, User> userRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, User> template = new RedisTemplate<Object, User>();
        template.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer<User> ser = new Jackson2JsonRedisSerializer<User>(User.class);
        template.setDefaultSerializer(ser);
        return template;
    }


    @Bean
    public RedisCacheManager UserCacheManager(RedisTemplate<Object, User> userRedisTemplate){
        RedisCacheManager cacheManager = new RedisCacheManager(userRedisTemplate);
        //前缀
        cacheManager.setUsePrefix(true);
        return cacheManager;
    }


}

如果存在多个实体类需要序列化的时候,那我们就要指定多个RedisTemplate和多个CacheManger:

package com.chtw.config;

import com.chtw.entity.User;
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.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.*;

import java.net.UnknownHostException;
import java.time.Duration;

@Configuration
public class MyRedisConfig {

    @Bean
    public RedisTemplate<Object, User> userRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, User> template = new RedisTemplate<Object, User>();
        template.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer<User> ser = new Jackson2JsonRedisSerializer<User>(User.class);
        template.setDefaultSerializer(ser);
        return template;
    }


    @Bean
    public RedisCacheManager UserCacheManager(RedisTemplate<Object, User> userRedisTemplate){
        RedisCacheManager cacheManager = new RedisCacheManager(userRedisTemplate);
        //前缀
        cacheManager.setUsePrefix(true);
        return cacheManager;
    }

    @Bean
    public RedisTemplate<Object, People1> peopleRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, People1> template = new RedisTemplate<Object, People1>();
        template.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer<User> ser = new Jackson2JsonRedisSerializer<People1>(User.class);
        template.setDefaultSerializer(ser);
        return template;
    }


    @Bean
    public RedisCacheManager PeopleCacheManager(RedisTemplate<Object, People1> peopleRedisTemplate){
        RedisCacheManager cacheManager = new RedisCacheManager(peopleRedisTemplate);
        //前缀
        cacheManager.setUsePrefix(true);
        return cacheManager;
    }

}

然后再在每一个service层上通过cacheconfig指定CacheManager:

3.2 springboot 2.x自定义CacheManger

Spring Boot2.X 与Spring Boot1.X 有很大不同,Spring Boot2 底层源码是:

那我们也可以模仿这个来写我们的自定义的CacheManager:

package com.chtw.config;


import com.chtw.entity.User;
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.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.*;

import java.net.UnknownHostException;
import java.time.Duration;

@Configuration
public class MyRedisConfig {


    @Primary  //将某个缓存管理器作为默认的
    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory){
        RedisCacheConfiguration cacheConfiguration =
                RedisCacheConfiguration.defaultCacheConfig()
                        .entryTtl(Duration.ofDays(1))
                        .disableCachingNullValues()
                        .serializeValuesWith(RedisSerializationContext.SerializationPair
                                .fromSerializer(new GenericJackson2JsonRedisSerializer()));
        return RedisCacheManager.builder(connectionFactory).cacheDefaults(cacheConfiguration).build();
    }

}

这样写好后,然后运行项目,访问我们的查询接口,就可以看到,redis中就是以json的方式存放的数据了。

本节类容到此结束

本人联系方式2329095893,欢迎各位进行学习讨论

欢迎关注熊熊出没ING公众号,不定时跟新Java、python、信息安全等相关知识哦。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值