Springboot集成Redis(三)

1. 配置Redis

1.1. 引入Redis依赖包
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-redis</artifactId>
</dependency>
1.2. 自动装配原理

在项目包libraries下面找到spring-boot-autoconfigure包;在这个包下面有一个spring.factories文件,此文件存放了所有springboot自动装配类的配置信息,以下是redis相关的配置

# mongo的自动装配相关类
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
# redis的自动装配相关类
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\

springboot所有的配置类都会有一个自动配置类,redis是RedisAutoConfiguration

自动配置类都会绑定一个properties,redis是RedisProperties

RedisAutoConfiguration源码如下:

  1. 引入了lettuce和jedis的连接配置类,springboot2.X以上版本redis连接都是用的lettuce作为连接客户端,2.X版本之下用的是jedis客户端!
  2. lettuce客户端:底层连接是基于netty实现的,实例可以在多线程之间实现共享!其调用方法是异步的,lettuce的api接口是线程安全的,方法调用主要采用NIO方式!
  3. jedis客户端:采用直连的连接方式,使用的阻塞IO,即BIO,性能低,多线程环境下是不安全的,一般可以使用jedispool连接池解决!
@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {

	@Bean
	@ConditionalOnMissingBean(name = "redisTemplate")
	public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
			throws UnknownHostException {
        //默认的redistemplate是没有过多配置的,redis对象都是需要序列化的
        //两个泛型都是object,我们后续使用最好是使用RedisTemplate<String, Object>
		RedisTemplate<Object, Object> template = new RedisTemplate<>();
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}

	@Bean
	@ConditionalOnMissingBean
	public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory)
			throws UnknownHostException {
        //string类型是redis中的常见类型,故单独为其提供的操作客户端
		StringRedisTemplate template = new StringRedisTemplate();
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}

}

RedisProperties配置项:

@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {

	/**
	 * 默认连接0号数据库
	 */
	private int database = 0;

	/**
	 * Connection URL:包括 host, port, and password.
	 * redis://user:password@example.com:6379
	 */
	private String url;

	/**
	 * Redis server host. 默认是本地地址
	 */
	private String host = "localhost";

	/**
	 * Login password of the redis server.
	 */
	private String password;

	/**
	 * Redis server port. 默认6379
	 */
	private int port = 6379;

	/**
	 * Whether to enable SSL support.
	 */
	private boolean ssl;

	/**
	 * Connection timeout.
	 */
	private Duration timeout;

    /**
	 * 哨兵模式配置
	 */
	private Sentinel sentinel; 

     /**
	 * 集群配置
	 */
	private Cluster cluster;
1.3. 配置文件
spring:
  redis:
    host: localhost
    port: 6379
    password: 123456

2.RedisTemplate

2.1. 基本APi

五大基本数据类型和三大特殊类型

redisTemplate.opsForValue(); //操作string类型
redisTemplate.opsForHash(); //操作hash
redisTemplate.opsForList(); //操作list
redisTemplate.opsForSet(); //操作set
redisTemplate.opsForZSet(); //操作zset
redisTemplate.opsForGeo(); //操作geo
redisTemplate.opsForHyperLogLog(); //操作HyperLogLog

事务

redisTemplate.multi(); //开启事务
redisTemplate.exec(); //执行事务
redisTemplate.discard(); //取消事务
redisTemplate.watch(null); //监控数据
redisTemplate.unwatch(); //取消监控

连接

RedisConnectionFactory connectionFactory = redisTemplate.getConnectionFactory();
RedisConnection connection = connectionFactory.getConnection();
connection.flushDb(); //清空数据库
connection.flushAll(); //清空所有数据

简单使用RedisTemplate

package com.acx;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

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

    private static final Logger logger = LoggerFactory.getLogger(RedisTemplateTest.class);

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void templateUse(){
        redisTemplate.opsForValue().set("user1","zhangsan");
        redisTemplate.opsForValue().set("user2","李四");
        System.out.println(redisTemplate.opsForValue().get("user1"));
        System.out.println(redisTemplate.opsForValue().get("user2"));
    }

}

执行结果(控制台):

zhangsan
李四

执行结果(redis服务器):key和value都会出现前缀占位符

本机redis_01:0>keys *
 1)  "\xAC\xED\x00\x05t\x00\x05user1"
 2)  "\xAC\xED\x00\x05t\x00\x05user2"
本机redis_01:0>get \xAC\xED\x00\x05t\x00\x05user1
"\xAC\xED\x00\x05t\x00\x08zhangsan"
本机redis_01:0>get \xAC\xED\x00\x05t\x00\x05user2
"\xAC\xED\x00\x05t\x00\x06\xE6\x9D\x8E\xE5\x9B\x9B"

查看RedisTemplate源码可知:

​ RedisTemplate默认使用的是JdkSerializationRedisSerializer序列化转换器,所以服务器端的key和value都会出现前缀占位符。

if (defaultSerializer == null) {

			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;
			}
		}
2.2. 自定义RedisTemplate

解决问题思路:

  1. key要使用string序列化器
  2. value使用jackson或者fastjson等主流的序列化器
  3. 被序列化对象需要实现Serializable接口
  4. 使用RedisTemplate<String, Object>
2.2. 自定义RedisTemplate
package com.acx.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.net.UnknownHostException;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
            throws UnknownHostException {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        Jackson2JsonRedisSerializer jacksonSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        //配置json序列化的规则
        // 指定要序列化的域,ALL代表包括类的field,get和set,以及修饰符范围,ANY是包括private和public
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jacksonSerializer.setObjectMapper(om);

        //字符串序列化类
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        //配置key value序列化规则
        template.setKeySerializer(stringRedisSerializer);
        template.setValueSerializer(jacksonSerializer);
        //配置hash的key value序列化规则
        template.setHashKeySerializer(stringRedisSerializer);
        template.setHashValueSerializer(jacksonSerializer);
        //将RedisTemplate属性进行重新配置
        template.afterPropertiesSet();
        return template;
    }

}

测试代码

  • user类:
package com.acx.pojo;

import java.io.Serializable;

public class User implements Serializable {

    private String name;

    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
    
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
  • 测试类:
  @Test
    public void testUser() {
        User user = new User();
        user.setName("张三");
        user.setAge(34);
        redisTemplate.opsForValue().set("user", user);
        System.out.println((User) redisTemplate.opsForValue().get("user"));
    }

测试结果(控制台):

User{name='张三', age=34}

测试结果(redis服务器):我们发现存在服务器里面的值带上了类名地址,如果微服务中其它的项目没有使用Jackson2JsonRedisSerializer序列化器的话则会导致数据无法解析,故保险起见最好还是将对象转换为json字符串以后再存入redis库,即不配置Jackson2JsonRedisSerializer序列化器。具体使用请根据具体业务实现

本机redis_01:0>keys *
 1)  "user"
本机redis_01:0>get user
"["com.acx.pojo.User",{"name":"张三","age":34}]"
本机redis_01:0>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值