spring-boot-starter-data-redis源码解析与使用实战

37 篇文章 5 订阅

我们以spring-boot-starter-data-redis-2.1.7为例,starter本身没有包含任何代码,只是引入了spring-data-redis的依赖,因此肯定是在spring-boot-autoconfigure中加了自动配置:
在这里插入图片描述
我们就看下这几个配置类:

其中RedisAutoConfiguration里面就配置了我们常用的RedisTemplate,RedisRepositoriesAutoConfiguration这里面是实现了spring-data规范的一些配置,RedisReactiveAutoConfiguration是当需要用Reactive方式编程的时候用的,本文忽略。

RedisAutoConfiguration


@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
//内置了对lettuce和jedis的支持
//但是默认只添加了lettuce的依赖,因此默认是使用的lettuce
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
    RedisTemplate<Object, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(redisConnectionFactory);
return template;
  }
@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
    StringRedisTemplate template = new StringRedisTemplate();
    template.setConnectionFactory(redisConnectionFactory);
return template;
  }
}

这里面内置了对lettuce和jedis的支持,因为默认是引入的lettuce的jar,因此默认会使用lettuce去访问redis,同时这里面创建了一个RedisTemplate和一个StringRedisTemplate,一般我们经常会直接注入StringRedisTemplate来访问redis。

StringRedisTemplate
public StringRedisTemplate() {
    setKeySerializer(RedisSerializer.string());
    setValueSerializer(RedisSerializer.string());
    setHashKeySerializer(RedisSerializer.string());
    setHashValueSerializer(RedisSerializer.string());
}

从名字也可以看出来,它在序列化key、value、hash key和hash value的时候都是转化成String存入redis的,RedisSerializer#string:

static RedisSerializer<String> string() {
    return StringRedisSerializer.UTF_8;
}
public static final StringRedisSerializer UTF_8 = 
    new StringRedisSerializer(StandardCharsets.UTF_8);

看下具体的序列化和反序列化的方法:

@Override
public String deserialize(@Nullable byte[] bytes) {
  return (bytes == null ? null : new String(bytes, charset));
}
@Override
public byte[] serialize(@Nullable String string) {
  return (string == null ? null : string.getBytes(charset));
}

一眼就能明白,没什么好说的。但是很显然,它只能处理String类型,如果是对象得需要自己手动转化成String才可以,一般我们会把对象转化成json字符串存储到redis里面。

RedisTemplate

RedisTemplate#afterPropertiesSet:

 @Override
  public void afterPropertiesSet() {
    boolean defaultUsed = false;
    //判断是否幽默ren的序列化器
    if (defaultSerializer == null) {
      //默认是采用jdk自带的序列化,
      //也就是说必须得实现Serializable接口才行
      defaultSerializer = new JdkSerializationRedisSerializer(
          classLoader != null ? classLoader : this.getClass().getClassLoader());
    }
    //默认j就是启用的
    if (enableDefaultSerializer) {
      //key、value、hash key、hash value都使用默认的那个序列化器 
      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默认是采用JDK自带的序列化方式来做序列化器,看一下:


public JdkSerializationRedisSerializer(@Nullable ClassLoader classLoader) {
    this(new SerializingConverter(), new DeserializingConverter(classLoader));
 }
 public SerializingConverter() {
    this.serializer = new DefaultSerializer();
  }
public class DefaultSerializer implements Serializer<Object> {
  @Override
  public void serialize(Object object, OutputStream outputStream) throws IOException {
    if (!(object instanceof Serializable)) {
      throw new IllegalArgumentException(getClass().getSimpleName() + " requires a Serializable payload " +
          "but received an object of type [" + object.getClass().getName() + "]");
    }
    ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
    objectOutputStream.writeObject(object);
    objectOutputStream.flush();
  }
}

很清楚了,最终是使用ObjectOutputStream和ObjectInputStream来读写对象,因此对象必须得实现Serializable接口才可以,最终是以二进制的格式存储到redis里面,比如:
在这里插入图片描述
很显然,这种序列化方式的可读性太不友好了。

RedisRepositoriesAutoConfiguration

它实现了spring-data规范,其实就是把redis以数据库dao的形式来访问,这个东西相对就比较复杂了,但是在实际中使用的并不是很多,我们只说一下如何使用。

首先定义一个dao,需要继承CrudRepository:

@Repository
public interface UserDao extends CrudRepository<UserEntity,Long> {
}

定义一个数据库实体:

@RedisHash("user")
public class UserEntity {
    @Id
    private Long id;
    private String username;
    private String password;
}

@RedisHash(“user”)会把user对象存储到一个key是user:id的hash中,比如:
在这里插入图片描述
定义service和controller:


@Service
public class UserService {
    @Autowired
    private UserDao userDao;
    public UserEntity save(UserEntity userEntity){
        userDao.save(userEntity);
        return userEntity;
    }
    public UserEntity findById(Long id){
        Optional<UserEntity> optional = userDao.findById(id);
        return optional.isPresent()?optional.get():null;
    }
}
@RestController
public class UserController {
    @Autowired
    private UserService userService;
    private static AtomicLong id = new AtomicLong(0);
    @GetMapping("/add_user")
    public String addUser(String username, String password){
        long idLong = id.incrementAndGet();
        userService.save(new UserEntity(idLong, username, password));
        UserEntity entity = userService.findById(idLong);
        return entity.toString();
    }
}

总结一下

  • 1.spring-boot-starter-data-redis默认是使用lettuce去访问redis

  • 2.内置了StringRedisTemplate和RedisTemplate,应用可以直接使用。当存取对象的时候,StringRedisTemplate需要手动把对象转化成String,RedisTemplate虽然可以直接存取对象,但是需要对象实现Serializable接口,同时在redis库中的可读性比较差。

  • 3.由于存在以上的缺点,因此可以把这两个template的优点给融合到一起,既可以直接存取对象,还可以方便人类阅读,当然也可以存取List和基本类型,更重要的是还可以支持给key统一添加前缀,赶快来使用吧:github地址:https://github.com/xjs1919/redis-client

欢迎扫码查看更多文章:
在这里插入图片描述

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值