- Jedis是Redis的Java实现的客户端,其API提供了比较全面的Redis命令的支持;
- Jedis中的方法调用是比较底层的暴露的Redis的API,也即Jedis中的Java方法基本和Redis的API保持着一致,了解Redis的API,也就能熟练的使用Jedis。
- Jedis在实现上是直接连接的redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个Jedis实例增加物理连接(像BIO)
- 使用阻塞的I/O,且其方法调用都是同步的,程序流需要等到sockets处理完I/O才能执行,不支持异步。Jedis仅支持基本的数据类型如:String、Hash、List、Set、Sorted Set。
为什么说Jedis是非线程安全的呢?
Lettuce因为发送命令和获取返回值时使用全局变量RedisOutputStream和RedisInputStream(redis.clients.jedis.Connection类中)。
当不同的线程在set和get的时候,有可能会出现线程A的set()的响应流,被线程B的get()作为返回了,所以出现了线程安全问题。
通过JedisPool连接池去管理实例,在多线程情况下让每个线程有自己的独立的jedis实例,从而避免了线程安全问题。
- Lettuce 是一个可伸缩的线程安全的 Redis 客户端,支持同步、异步和响应式模式。多个线程可以共享一个连接实例,而不必担心多线程并发问题。支持Redis 的高级功能,如 Sentinel,集群,流水线,自动重新连接和 Redis 数据模型
- Lettuce的连接是基于Netty的,连接实例(StatefulRedisConnection)可以在多个线程间并发访问,因为StatefulRedisConnection是线程安全的,所以一个连接实例(StatefulRedisConnection)就可以满足多线程环境下的并发访问,当然这个也是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例.
- 高级Redis客户端,用于线程安全同步,异步和响应使用,支持集群,Sentinel,管道和编码器。
- 基于Netty框架的事件驱动的通信层(NIO),其方法调用是异步的。Lettuce的API是线程安全的,所以可以操作单个Lettuce连接来完成各种操作。
- springboot2.0之后,原来使用的Jedis 被替换为Lettuce
- Redisson实现了分布式和可扩展的Java数据结构,提供很多分布式相关操作服务,例如,分布式锁,分布式集合,可通过Redis支持延迟队列。和Jedis相比,功能较为简单,不支持字符串操作,不支持排序、事务、管道、分区等Redis特性。Redisson的宗旨是促进使用者对Redis的关注分离,从而让使用者能够将精力更集中地放在处理业务逻辑上。
- Redisson中的方法则是进行比较高的抽象,每个方法调用可能进行了一个或多个Redis方法调用。
- 基于Netty框架的事件驱动的通信层,其方法调用是异步的。Redisson的API是线程安全的,所以可以操作单个Redisson连接来完成各种操作。
- Redisson不仅提供了一系列的分布式Java常用对象,基本可以与Java的基本数据结构通用,还提供了许多分布式服务,其中包括(BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service, Scheduler service)。
application.properties 配置文件org.springframework.boot spring-boot-starter-data-redis
spring.redis.host=xxx.xxx.xxx.xxx spring.redis.port=6379 spring.redis.password= #连接超时时间(毫秒) spring.redis.timeout=10000ms # 连接池最大连接数(使用负值表示没有限制) 默认 8 spring.redis.lettuce.pool.max-active=8 # 连接池中的最大空闲连接 默认 8 spring.redis.lettuce.pool.max-idle=8 # 连接池最大阻塞等待时间,单位毫秒(使用负值表示没有限制) 默认 -1 spring.redis.lettuce.pool.max-wait=1000ms # 连接池中的最小空闲连接 默认 0 spring.redis.lettuce.pool.min-idle=0 spring.redis.lettuce.shutdown-timeout=100msSpringbootRedisApplicationTests :
自动注入容器中的redisTemplate 实例(在redis的自动装配里面会给spring容器注入一个redisTemplate实例),而redisTemplate 是封装了对redis数据库的一系列操作
@SpringBootTest
class SpringbootRedisApplicationTests {
@Autowired
private RedisTemplate
成功连接上服务器上的redis完成基本操作
在不是应用基本数据结构的情况下,比如实体类的情况下,我们需要对实体类进行序列化
User 类(使用lombok插件,减少手写setter/getter,constructor方法)
@Component
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {
private String name;
private int age;
private String sex;
}
SpringbootRedisApplicationTests 新加一个test方法
@Test
public void test() throws JsonProcessingException {
User user = new User("xt",23,"男");
//将对象转化为json格式的字符串
String jsonuser = new ObjectMapper().writevalueAsString(user);
System.out.println(jsonuser);
redisTemplate.opsForValue().set("userXT",jsonuser);
System.out.println(redisTemplate.opsForValue().get("userXT"));
}
如果不传入序列化后的key,value,或者不能实现序列化的key,value,就会引发以下异常
要缓存的JavaBean必须实现Serializable接口,因为Spring会将对象先序列化再存入 Redis
使用springboot-data-redis,默认情况下是使用org.springframework.data.redis.serializer.JdkSerializationRedisSerializer这个类来做序列化
所以你也可以给实体类上实现Serializable接口
public class User implements Serializable自定义工具类
我们可以自己封装一个工具类,以redisTemplate的API为基础,再度封装。先在工具类中注入spring容器中的redisTemplate
@Component
public final class RedisUtil {
@Autowired
private RedisTemplate
在使用的地方注入redisUtil 实例即可,@Component标注的RedisUtil, Spring 会帮我们生成redisUtil实例
@SpringBootTest
class SpringbootRedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private RedisUtil redisUtil;
@Test
void contextLoads() {
System.out.println(redisTemplate);
redisTemplate.opsForValue().set("name","xt");
System.out.println(redisTemplate.opsForValue().get("name"));
}
@Test
public void test() throws JsonProcessingException {
User user = new User("xt",23,"男");
//将对象转化为json格式的字符串
// String jsonuser = new ObjectMapper().writevalueAsString(user);
// System.out.println(jsonuser);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.opsForValue().set("userXT", user);
System.out.println(redisTemplate.opsForValue().get("userXT"));
}
@Test
public void testRedisUtils(){
System.out.println(redisUtil);
User user = new User("xt",23,"男");
redisUtil.set("userXT",user);
System.out.println(redisUtil.get("userXT"));
}
}
扩展阅读
meta-INF/spring.factories文件的作用是什么
查看 spring-data-redis jar包的信息包文件夹meta-INF下的 spring.factories,仅有一个 RepositoryFactorySupport 并无自动装配。
org.springframework.data.repository.core.support.RepositoryFactorySupport=org.springframework.data.redis.repository.support.RedisRepositoryFactory
在下载的jar包文件中,我们可以看到有个spring-boot-autoconfigure jar包
在 jar包的信息包文件夹meta-INF中的spring.factories文件
里面有这样的一部分配置,key是org.springframework.boot.autoconfigure.EnableAutoConfiguration,value是各个以逗号隔开的*AutoConfiguration,结合spring-factories的运行原理,我们就可以知道所有的自动配置是从这里开始加载的。
可以在这个文件中找到redis的自动配置类RedisAutoConfiguration
把鼠标放到自动配置类RedisAutoConfiguration上 按 Ctrl-B 进入,看见他会帮我们new一个RedisTemplate实例(redisTemplate)放到spring的IOC容器中
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({RedisOperations.class})
@EnableConfigurationProperties({RedisProperties.class})
@import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
public RedisAutoConfiguration() {
}
@Bean
@ConditionalOnMissingBean(
name = {"redisTemplate"}
)
//当这个redisTemplate bean实例不存在,下面的这个方法就生效
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
return new StringRedisTemplate(redisConnectionFactory);
}
}
@Configuration
用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。
proxyBeanMethods参数设置为false时即为:Lite 轻量级模式。该模式下注入容器中的同一个组件无论被取出多少次都是不同的bean实例,即多实例对象,在该模式下SpringBoot每次启动会跳过检查容器中是否存在该组件
什么时候用Full全模式,什么时候用Lite轻量级模式?
当在你的同一个Configuration配置类中,注入到容器中的bean实例之间有依赖关系时,建议使用Full全模式;当在你的同一个Configuration配置类中,注入到容器中的bean实例之间没有依赖关系时,建议使用Lite轻量级模式,以提高springboot的启动速度和性能
@ConditionalOnClass表示只有classpath中能找到RedisOperations.class时,RedisAutoConfiguration这个类才会被spring容器实例化,这其实也解释了为什么我们有时候只需要在pom.xml添加某些依赖包,某些功能就自动打开了
关与 @EnableConfigurationProperties 注解
@EnableConfigurationProperties引入了RedisProperties的配置,将使用了@ConfigurationProperties 注解的RedisProperties类生效,注入到spring的容器中
@import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
@EnableConfigurationProperties({RedisProperties.class})
Ctrl-B 进入RedisProperties类,我们可以看到他里面封装了很多属性,host和port有默认值
我们也可以发现application.properties中的前缀为spring.redis的配置是用在这里面的
注解@ConfigurationProperties
redis 配置由 springBoot 集成,在 spring-boot-autoconfigure 中配置,spring.factories 中 EnableAutoConfiguration 指定自动配置类 RedisAutoConfiguration 进行自动配置,spring-configuration-metadata.properties 指定了配置元数据 RedisAutoConfiguration ConditionalOnClass 配置条件 RedisOperations,当引入 spring-data-redis 时存在类路径 RedisOperations 进行 redis 的自动加载。redis 自动配置使用 Lettuce 作为 client 进行连接,配置了默认的 bean redisTemplate、StringRedisTemplate。
@ConditionalOnMissingBean表示在Spring容器中如果有一个Bean的name是redisTemplate那将不需要再执行被此注解修饰的代码块,也就是此方法。
如果我们自己写了一个redisTemplate bean,那么我们获取的就是自己写的那个bean 实例。
redisTemplate 里面通过set注入了一个redisConnectionFactory
@Bean
@ConditionalOnMissingBean(
name = {"redisTemplate"}
)
//当这个redisTemplate bean实例不存在,下面的这个方法就生效
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
redisConnectionFactory是一个接口,里面提供了两个实现
分别是JedisConnectionFactory 和 LettuceConnectionFactory
进入JedisConnectionFactory类,点击右上角悬浮条下载源码
可以发现很多类会爆红,无法引入(springboot 2.0 已经抛弃 Jedis)
但是LettuceConnectionFactory不会出现这种情况
要缓存的JavaBean必须实现Serializable接口,因为Spring会将对象先序列化再存入 Redis
RedisTemplate 有如下字段需要序列化
@SuppressWarnings("rawtypes") private @Nullable RedisSerializer keySerializer = null;
@SuppressWarnings("rawtypes") private @Nullable RedisSerializer valueSerializer = null;
@SuppressWarnings("rawtypes") private @Nullable RedisSerializer hashKeySerializer = null;
@SuppressWarnings("rawtypes") private @Nullable RedisSerializer hashValueSerializer = null;
默认的序列化方式是JDK序列化
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;
}
}
当然你也可以自己修改redisTemplate指定的序列化实现类
public void setKeySerializer(RedisSerializer> serializer) {
this.keySerializer = serializer;
}
RedisSerializer是一个Redis序列化的接口,我们可以看到这个接口又有很多的实现类
- https://blog.csdn.net/liujun03/article/details/82891784
- https://www.bilibili.com/video/BV1S54y1R7SB?p=25
- https://xie.infoq.cn/article/59431718520a87b1a59b5ef9a
- https://cloud.tencent.com/developer/article/1500854
- https://www.cnblogs.com/myitnews/p/13733882.html
- https://blog.csdn.net/song_java/article/details/86509971



