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

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配置

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

想知道都支持那些属性配置的?

  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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,009评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,808评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,891评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,283评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,285评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,409评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,809评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,487评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,680评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,499评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,548评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,268评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,815评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,872评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,102评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,683评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,253评论 2 341

推荐阅读更多精彩内容