Spring boot 配置多个 redis

2,751 阅读2分钟

单个 RedisTemplate 的配置

使用 spring-boot-starter-data-redis 配置一个 redis 是很简单的。 pom.xml 中该引入的依赖是要引入的,下面的是完整的 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>me.deweixu</groupId>
	<artifactId>muti-redis</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>muti-redis</name>
	<description>config mutiple redis host</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.4.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

application.properties 文件增加相关的配置

spring.redis.host=localhost
spring.redis.port=6379

简单的配置就是这样的,还有一些有关连接池或其他的详细配置可以在 common-application-properties 中参考,或者直接查看 RedisProperties 类。

这里使用 redis 的例子我就直接在主类中示例了。

package me.deweixu.mutiredis;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.StringRedisTemplate;

@SpringBootApplication
public class MutiRedisApplication implements CommandLineRunner {

	@Autowired
	StringRedisTemplate stringRedisTemplate;

	@Override
	public void run(String... args) throws Exception {
		BoundValueOperations op = stringRedisTemplate.boundValueOps("PERSON");
		op.set("Deweixu");
	}

	public static void main(String[] args) {
		SpringApplication.run(MutiRedisApplication.class, args);
	}
}

直接运行起来,然后去 redis 查看结果:

$ redis-cli
127.0.0.1:6379> keys *
1) "PERSON"
127.0.0.1:6379> get PERSON
"Deweixu"
127.0.0.1:6379>

没问题的,顺利的把数据存入到了 redis 中。

自定义 RedisTemplate 的序列类

上面的实现其实有一个问题,就是 rediskeyvalue 只能是 String 类型的,是 redis-starter 默认实现了的一个 StringRedisTemplate。查看其源代码是这样的

    public StringRedisTemplate() {
        RedisSerializer<String> stringSerializer = new StringRedisSerializer();
        this.setKeySerializer(stringSerializer);
        this.setValueSerializer(stringSerializer);
        this.setHashKeySerializer(stringSerializer);
        this.setHashValueSerializer(stringSerializer);
    }

如果使用 StringRedisTemplate 存入一个对象是要报错的,我们修改一下代码试试:

	@Autowired
	StringRedisTemplate stringRedisTemplate;

	@Override
	public void run(String... args) throws Exception {
		BoundValueOperations op = stringRedisTemplate.boundValueOps("PERSON");
		op.set(new Person("Deiweixu", 22));
	}

	public static void main(String[] args) {
		SpringApplication.run(MutiRedisApplication.class, args);
	}

运行就报错如下:

Caused by: java.lang.ClassCastException: me.deweixu.mutiredis.MutiRedisApplication$Person cannot be cast to java.base/java.lang.String
	at org.springframework.data.redis.serializer.StringRedisSerializer.serialize(StringRedisSerializer.java:35) ~[spring-data-redis-2.0.9.RELEASE.jar:2.0.9.RELEASE]
	at org.springframework.data.redis.core.AbstractOperations.rawValue(AbstractOperations.java:126) ~[spring-data-redis-2.0.9.RELEASE.jar:2.0.9.RELEASE]
	at org.springframework.data.redis.core.DefaultValueOperations.set(DefaultValueOperations.java:197) ~[spring-data-redis-2.0.9.RELEASE.jar:2.0.9.RELEASE]
	at org.springframework.data.redis.core.DefaultBoundValueOperations.set(DefaultBoundValueOperations.java:110) ~[spring-data-redis-2.0.9.RELEASE.jar:2.0.9.RELEASE]
	at me.deweixu.mutiredis.MutiRedisApplication.run(MutiRedisApplication.java:19) [classes/:na]
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:800) [spring-boot-2.0.4.RELEASE.jar:2.0.4.RELEASE]
	... 5 common frames omitted

这样我们可以自己配置一下序列化类,这里我们把对象序列化为一个 json 存入到 redis

	@Autowired
	RedisConnectionFactory redisConnectionFactory;

	@Bean
	RedisTemplate<String, Object> firstRedisTemplate() {
		RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        ObjectMapper om = new ObjectMapper();
		om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
		om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
		om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(om);
		redisTemplate.setKeySerializer(new StringRedisSerializer());
		redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
		redisTemplate.setHashKeySerializer(new StringRedisSerializer());
		redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
		redisTemplate.setConnectionFactory(redisConnectionFactory);
		return redisTemplate;
	}

	@Autowired
	RedisTemplate<String, Object> redisTemplate;

	@Override
	public void run(String... args) throws Exception {
		BoundValueOperations<String, Object> op = redisTemplate.boundValueOps("PERSON");
		People people = new People();
		people.setAge(26);
		people.setName("Deweixu");
		op.set(people);
		People getPeople = (People) op.get();
		System.out.println(getPeople.getName() + "," + getPeople.getAge());
	}

上面使用了 Jedis 的配置和 GenericJackson2JsonRedisSerializer 类,所以 maven 要引入依赖

<dependency>
	<groupId>com.fasterxml.jackson.core</groupId>
	<artifactId>jackson-databind</artifactId>
	<version>2.9.0</version>
</dependency>
<dependency>
	<groupId>redis.clients</groupId>
	<artifactId>jedis</artifactId>
</dependency>

这样运行可以看到 redis 中变成这样了:

127.0.0.1:6379> get PERSON
"[\"me.deweixu.mutiredis.entity.People\",{\"name\":\"Deweixu\",\"age\":26}]"
127.0.0.1:6379>

配置另外一个 redisTemplate

	@Bean
	RedisTemplate<String, Object> secondRedisTemplate() {
		RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
		ObjectMapper om = new ObjectMapper();
		om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
		om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
		om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(om);
		redisTemplate.setKeySerializer(new StringRedisSerializer());
		redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
		redisTemplate.setHashKeySerializer(new StringRedisSerializer());
		redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
        // 这里的 redis 信息也是可以写入配置文件,用 @Value 读入
        // 这里是单机的配置,看看源代码还可以配置集群和哨兵模式
		RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration("localhost", 6379);
		JedisConnectionFactory factory = new JedisConnectionFactory(configuration);
		redisTemplate.setConnectionFactory(factory);
		return redisTemplate;
	}

注入 secondRedisTemplate 即可

	@Autowired
	RedisTemplate<String, Object> firstRedisTemplate;

	@Autowired
	RedisTemplate<String, Object> secondRedisTemplate;

	@Override
	public void run(String... args) throws Exception {
		BoundValueOperations<String, Object> op = firstRedisTemplate.boundValueOps("PERSON");
		People people = new People();
		people.setAge(26);
		people.setName("Deweixu");
		op.set(people);
		BoundValueOperations<String, Object> secondOp = secondRedisTemplate.boundValueOps("PERSON");
		People getPeople = (People) secondOp.get();
		System.out.println(getPeople.getName() + "," + getPeople.getAge());
	}