spring-boot 整合redis(简单整合含源码)

spring-boot 整合redis

技术版本说明

1. springboot .version - 2.2.2.RELEASE
2. jdk .version - 8
3. lombok.version  - version  - 1.18.10
4. hutool-all.version - 5.6.2
5. spring-boot-starter-data-redis。version - 延用springboot里的版本(即 2.2.2.RELEASE)
6. fastjson - version - 1.2.75

源码地址

gitee地址: https://gitee.com/zjydzyjs/spring-boot-use-case-collection/tree/master/spring-boot-no-sql/redis

yml配置说明

如下图(yml配置):

yml配置

yml 配置(图)

备注: 我这里只是简单配置,如果需要自定义复杂配置,请自行配置;

想知道都支持那些属性配置的?
  1. 请搜索类 {@link RedisProperties.class};
package: org.springframework.boot.autoconfigure.data.redis
下的
RedisProperties.class
  1. 直接通过点击yml配置中的jedis里的最后一层内容即可跳转到具体类,例如点击application-dev.yml 中的max-idle 属性;

  2. 通过找寻Redis自动配置类来找到具体的属性配置;

自动配置文件

右边 RedisAutoConfiguration 点击进去,即可找到

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnClass({RedisOperations.class})
@EnableConfigurationProperties({RedisProperties.class})
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
    public RedisAutoConfiguration() {
    }
	// 省略
	......
}

@EnableConfigurationProperties 可以得知Redis配置类是RedisProperties.class

不进行序列化配置和序列化配置后进行测试

spring-boot-starter-data-redis 封装了对象用于对redis的操作,你可以理解为这是spring-boot帮我们写好了一个用于操作redis的工具类(或服务类),这个类叫

RedisTemplate.class
public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware {
    private boolean enableTransactionSupport = false;
    private boolean exposeConnection = false;
    private boolean initialized = false;
    private boolean enableDefaultSerializer = true;
    @Nullable
    private RedisSerializer<?> defaultSerializer;
    @Nullable
    private ClassLoader classLoader;
    @Nullable
    private RedisSerializer keySerializer = null;
    @Nullable
    private RedisSerializer valueSerializer = null;
    @Nullable
    private RedisSerializer hashKeySerializer = null;
    @Nullable
    private RedisSerializer hashValueSerializer = null;
    private RedisSerializer<String> stringSerializer = RedisSerializer.string();
    @Nullable
    private ScriptExecutor<K> scriptExecutor;
    private final ValueOperations<K, V> valueOps = new DefaultValueOperations(this);
    private final ListOperations<K, V> listOps = new DefaultListOperations(this);
    private final SetOperations<K, V> setOps = new DefaultSetOperations(this);
    private final StreamOperations<K, ?, ?> streamOps = new DefaultStreamOperations(this, new ObjectHashMapper());
    private final ZSetOperations<K, V> zSetOps = new DefaultZSetOperations(this);
    private final GeoOperations<K, V> geoOps = new DefaultGeoOperations(this);
    private final HyperLogLogOperations<K, V> hllOps = new DefaultHyperLogLogOperations(this);
    private final ClusterOperations<K, V> clusterOps = new DefaultClusterOperations(this);

    public RedisTemplate() {
    }
	
    // 省略

 }
StringRedisTemplate

spring-boot 其实还封装了一个StringRedisTemplate.class 类,这个类是专门用于操作Key 、Value 都是String类型的,

public class StringRedisTemplate extends RedisTemplate<String, String> {
    public StringRedisTemplate() {
        this.setKeySerializer(RedisSerializer.string());
        this.setValueSerializer(RedisSerializer.string());
        this.setHashKeySerializer(RedisSerializer.string());
        this.setHashValueSerializer(RedisSerializer.string());
    }

    public StringRedisTemplate(RedisConnectionFactory connectionFactory) {
        this();
        this.setConnectionFactory(connectionFactory);
        this.afterPropertiesSet();
    }

    protected RedisConnection preProcessConnection(RedisConnection connection, boolean existingConnection) {
        return new DefaultStringRedisConnection(connection);
    }
}

StringRedisTemplate类中我们发现其实它对如下属性进行了设置:

​ private RedisSerializer keySerializer = null;
​ // 对Key序列化的RedisSerializer

​ private RedisSerializer valueSerializer = null;
​ //对Value序列化的RedisSerializer

​ private RedisSerializer hashKeySerializer = null;

​ // 对HashKey序列化的RedisSerializer

​ private RedisSerializer hashValueSerializer = null;

​ // 对hashValue序列化的RedisSerializer

为什么要设置呢?

从 this.afterPropertiesSet(); 中可以发现 在RedisTemplate.class中

public void afterPropertiesSet() {
    super.afterPropertiesSet();
    boolean defaultUsed = false;
    if (this.defaultSerializer == null) {
        // 当没有指定默认的序列化器时,默认使用JdkSerializationRedisSerializer 序列化器 (这里会出现很多的问题,后面写用例的时候我再说)
        this.defaultSerializer = new JdkSerializationRedisSerializer(this.classLoader != null ? this.classLoader : this.getClass().getClassLoader());
    }

     // 默认为true,所以key、value、hashKey、hashValue 都会使用自己设置的,如果没有设置的话就会使用this.defaultSerializer
    if (this.enableDefaultSerializer) { 
      
        if (this.keySerializer == null) {
            this.keySerializer = this.defaultSerializer;
            defaultUsed = true;
        }

        if (this.valueSerializer == null) {
            this.valueSerializer = this.defaultSerializer;
            defaultUsed = true;
        }

        if (this.hashKeySerializer == null) {
            this.hashKeySerializer = this.defaultSerializer;
            defaultUsed = true;
        }

        if (this.hashValueSerializer == null) {
            this.hashValueSerializer = this.defaultSerializer;
            defaultUsed = true;
        }
    }

    if (this.enableDefaultSerializer && defaultUsed) {
        Assert.notNull(this.defaultSerializer, "default serializer null and not all serializers initialized");
    }

    if (this.scriptExecutor == null) {
        this.scriptExecutor = new DefaultScriptExecutor(this);
    }

    this.initialized = true;
}
测试用例
String类型测试
// set String类型

@Test
void contextLoads() {
setStr();
}

void setStr(){
String keyStr = "testKey";
redisTemplate.opsForValue().set(keyStr,"testVal");
System.out.println("str:"+redisTemplate.opsForValue().get(keyStr));
}

结果:

RedisTemplate-String类型set

图中可以发现该key已经存在了,但是会存在很难直接理解的字符,那么这个是因为什么呢?

问题

其实,出现这个的原因就是因为我们现在使用的是RedisTemplate.class ,你可以打开你的这个类查看 afterPropertiesSet() 方法,也可以查看我上面写的StringRedisTemplate中描述的 “为什么要设置呢?” 那里,就可以知道,为什么会变成这样子,因为它使用了 JdkSerializationRedisSerializer 所以导致该String类型的数据,key和value都无法直接理解。

解决
  1. 使用StringRedisTemplate
  2. 自己封装一个RedisTemplate 用来注入到spring中
效果

StringRedisTemplate-set

StringRedisTemplate 效果

MyRedisConfig

// 增加MyRedisConfig配置

@Configuration
public class MyRedisConfig {

    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
    RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
    template.setConnectionFactory(factory);
    // 使用jackson 进行序列化
    this.jackson(template);
    //this.fastJson(template);
    template.afterPropertiesSet();
    return template;
    }

    private void jackson(RedisTemplate<String, Object> template){
    Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    ObjectMapper om = new ObjectMapper();
    om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    //        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    jackson2JsonRedisSerializer.setObjectMapper(om);
    StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
    // key采用String的序列化方式
    template.setKeySerializer(stringRedisSerializer);
    // value序列化方式采用jackson
    template.setValueSerializer(jackson2JsonRedisSerializer);
    // hash的key也采用String的序列化方式
    template.setHashKeySerializer(stringRedisSerializer);
    // hash的value序列化方式采用jackson
    template.setHashValueSerializer(jackson2JsonRedisSerializer);
    }
}

自定义配置RedisConfig

自定义Object类型类型测试

这里使用 T.class;

注意:测试的时候请先将MyRedisConfig注释,不然不会出现异常信息!

@Data
@AllArgsConstructor
public class T {
    private String name;
    private Integer index;
    private String value;
}
void setObj(){
    String keyObj = "obj";
    redisTemplate.opsForValue().set(keyObj,new T("testObj",1,"testVal"));
    System.out.println("obj:"+redisTemplate.opsForValue().get(keyObj));
问题

运行后出现异常:

org.springframework.data.redis.serializer.SerializationException: Cannot serialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to serialize object using DefaultSerializer; nested exception is java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type [com.blacktea.redis.dto.T]

怎么解决?

因为要使用Jdk序列化,所以T.class必须的实现接口 Serializable

@Data
@AllArgsConstructor
public class T implements Serializable {
    private static final long serialVersionUID = 1875172526779913430L;
    private String name;
    private Integer index;
    private String value;
}
效果

jdk序列化对象效果

这样还是会存在String类型测试那里的问题,可以使用 MyRedisConfig.class 自己配置解决,也可以手动把key、value自己转换成String。

手动转换,例如:

redisTemplate.opsForValue().set(keyObj, JSONUtil.toJsonStr(obj));
测试总结

你可以将key、value转换成String类型即可是实现在redis显示可以直观理解的内容。

将key、value 转化,可以通过实现 RedisSerializer 接口来自定义序列化处理。

可以参考:

FastJsonRedisSerializer.class
Jackson2JsonRedisSerializer.class
StringRedisSerializer.class
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值