前言
当SpringBoot项目需要整合Redis时,第一步肯定是先导入Redis的相关依赖(其实第一步应该先下载Redis服务,这里以本地已经安装好Redis为基础),然后再进行Redis相关配置。搞好以后,进行测试,没问题OK,有问题处理。下面就详细讲解SpringBot整合Redis的最基础过程(这里以SpringBoot3.1.5 + JDK17进行演示,其实和3以下的版本没什么区别)。
本文涉及知识点:@PropertySource、@Configuration、@Bean、Redis、Lombok
整合过程
下面是整合过程以及遇到的问题:
导入Redis依赖
通过SpringBoot官网了解,可以知道SpringBoot已经在起步依赖中整合了集成Redis所需要的相关依赖。所以不需要自己再去费心整合Redis所需要的相关依赖和兼顾版本之间的兼容性问题,直接引入spring-boot-starter-data-redis
即可。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
创建一个RedisInfo、redis.properties(涉及知识点:@PropertySource、Lombok)
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Repository;
@Repository
@Data
@PropertySource(value = "classpath:redis.properties")
public class RedisInfo {
@Value("${redis.host}")
private String host;
@Value("${redis.port}")
private Integer port;
@Value("${redis.pwd}")
private String pwd;
}
所在路径:src/main/resources/redis.properties
redis.host=localhost
redis.port=6379
redis.pwd=redis123
Lombok的@Data注解使用
首先使用Lombok需要导入相关依赖以及下载相关插件。
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional> <!--optional 标识这个依赖是可选的,主要用于父子依赖之间的传递性问题-->
</dependency>
下载Lombok插件:
@Data是Lombok库中的一个注解,用于简化Java类的编写。当你在一个类上使用@Data注解,Lombok会自动为你的类生成以下内容:
- Getter:对于类中的每个字段,生成一个公有的getter方法。
- Setter:对于类中的每个非final字段,生成一个公有的setter方法。
- equals() 和 hashCode():基于类中的所有字段,生成这两个方法。
- toString():自动生成一个返回类名和字段值的字符串的方法。
但请注意,使用@Data注解需要注意以下缺点和限制:
- 不支持多种参数构造器的重载:@Data注解会自动生成一个包含所有参数的构造器,但如果我们想要多个构造器,例如一个只包含部分参数的构造器,@Data就不能满足了。
- 过多的插件容易降低阅读源代码的舒适度:由于@Data注解会自动生成很多方法,如果IDE没有安装Lombok插件,那么源代码看起来会有很多红线(编译错误),对于未安装Lombok插件的开发者来说,阅读这样的代码会比较困难。
创建一个RedisConfiguration(涉及知识点:@Configuration、@Bean)
@Configuration // @Configuration 让SpringBoot知道这是一个配置类
public class RedisConfiguration {
@Resource
private RedisInfo redisInfo;
@Bean // @Bean 声明这是一个bean,bean的名称和方法名对应
public JedisConnectionFactory connectionFactory(){
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
configuration.setHostName(redisInfo.getHost());
configuration.setPort(redisInfo.getPort());
configuration.setPassword(redisInfo.getPwd());
JedisConnectionFactory connectionFactory = new JedisConnectionFactory(configuration);
return connectionFactory;
}
@Bean
public RedisTemplate<Object,Object> redisTemplate(JedisConnectionFactory connectionFactory){
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
template.setDefaultSerializer(new GenericJackson2JsonRedisSerializer());
return template;
}
}
这里我显式的定义了RedisTemplate和JedisConnectionFactory这两个类,其实是可以不进行显式定义的,因为当我导入了spring-boot-starter-data-redis
的那一刻,SpringBoot就会自动加载Redis的相关配置。是不是像魔法一样,这就是SpringBoot自动配置的魔法。
我这里对这个魔法进行进一步研究发现,在项目中有一个叫做spring-boot-autoconfigure-3.1.5.jar
的依赖,这个依赖下面 META-INF\spring
目录下有一个叫做org.springframework.boot.autoconfigure.AutoConfiguration.imports
的文件。打开这个文件可以看到里面有很多以Configuration结尾的配置类,这些就是SpringBoot为使用者整合的所有配置类。
然后Ctrl+F
搜索redis,可以发现总共有三个相关配置,如图:
RedisReactiveAutoConfiguration
属于响应式编程,不用管。
RedisRepositoriesAutoConfiguration
属于 JPA 操作,也不用管
RedisAutoConfiguration
是需要注意的,它配置了以下组件
LettuceConnectionConfiguration
: 给容器中注入了连接工厂LettuceConnectionFactory,和操作 redis 的客户端DefaultClientResources。RedisTemplate<Object, Object>
: 可给 redis 中存储任意对象,会使用 jdk 默认序列化方式。StringRedisTemplate
: 给 redis 中存储字符串,如果要存对象,需要开发人员自己进行序列化。key-value都是字符串进行操作。
这里我如果不写RedisConfiguration配置类,然后通过SpringBoot启动类来验证一下是否仍然有 template 的配置。
启动后在控制台搜索redis关键字可以看到SpringBoot已经装载好了这些Bean:
除了这些还有很多,其中就有我在上面看到的 redisTemplate
、stringRedisTemplate
、LettuceConnectionConfiguration
。这就是SpringBoot的自动装配原理魔法的一部分。
所以当我显式的定义了这些配置类以后,这些默认配置就会被覆盖掉,SpringBoot会优先使用显式的配置。除了显式配置我还可以进行隐式配置,也就是只覆盖掉默认配置的一部分,可以通过application.properties或者yml等形式来实现,这里就不过多阐述。
验证
然后接下来我将来验证整合好的Redis是否能正常的在项目中使用,同样我还是在启动类里面来测试。
@SpringBootApplication
public class Springboot3Application {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(Springboot3Application.class, args);
RedisTemplate redisTemplate = (RedisTemplate) run.getBean("redisTemplate");
System.out.println(redisTemplate);
redisTemplate.opsForValue().set("redis","123");
Object value = redisTemplate.opsForValue().get("redis");
System.out.println(value);
}
}
因为SpringApplication.run(Springboot3Application.class, args)
会返回一个ConfigurableApplicationContext
,所以我通过getBean
的方式获取到了redisTemplate
,并在缓存中设置了一些值,下面是执行结果:
嗯?直接抛错了,这是怎么回事?报错的位置是RedisConfiguration类的第33行。可是我并没有使用JedisPoolConfig这个类,那就是 JedisConnectionFactory connectionFactory = new JedisConnectionFactory(configuration);
这段代码里面用了,因为RedisConfiguration类的第33行就是这段代码。
难道是JedisConnectionFactory这个类里面使用到了JedisPoolConfig?带着这个疑问我点进去JedisConnectionFactory类文件看它的代码,嚯!全是报错:
这其中赫然就有JedisPoolConfig。
通过网上检索了解到这是因为缺少jedis
依赖导致的,只要引入下面依赖就可以了。
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
这个时候我就纳闷了,SpringBoot不是已经在起步依赖中整合了集成Redis所有需要的相关依赖了吗?为什么会缺少jedis
呢?
带着这个疑问我又点进去spring-boot-starter-data-redis
依赖中查找原因,点进去以后可以发现它包含了这些依赖项:
很明显,spring-data-redis
才是我要探索的,然后我就又点进去进行查看,通过Ctrl+F
找到了jedis
这个依赖,如图:
当我看到optional的时候,我就明白了,这个依赖虽然SpringBoot已经帮我们整理好,但是它是一个可选的依赖并不会强继承,所以需要在项目中显式的声明一下,版本可以不声明,因为显式声明以后项目就会继承这个依赖了。
接下来再启动项目,就没有任何报错了!
总结
- 导入Redis相关依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
- 编写Redis相关配置(可选)
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Repository;
@Repository
@Data
@PropertySource(value = "classpath:redis.properties")
public class RedisInfo {
@Value("${redis.host}")
private String host;
@Value("${redis.port}")
private Integer port;
@Value("${redis.pwd}")
private String pwd;
}
redis.host=localhost
redis.port=6379
redis.pwd=redis123
- 编写RedisConfiguration配置类(可选,也可通过properties或yml进行配置)
@Configuration // @Configuration 让SpringBoot知道这是一个配置类
public class RedisConfiguration {
@Resource
private RedisInfo redisInfo;
@Bean // @Bean 声明这是一个bean,bean的名称和方法名对应
public JedisConnectionFactory connectionFactory(){
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
configuration.setHostName(redisInfo.getHost());
configuration.setPort(redisInfo.getPort());
configuration.setPassword(redisInfo.getPwd());
JedisConnectionFactory connectionFactory = new JedisConnectionFactory(configuration);
return connectionFactory;
}
@Bean
public RedisTemplate<Object,Object> redisTemplate(JedisConnectionFactory connectionFactory){
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
template.setDefaultSerializer(new GenericJackson2JsonRedisSerializer());
return template;
}
}