springboot 2.3.3整合redis并基于Lettuce的实现

satuo20 1年前 ⋅ 435 阅读

springboot 2.3.3整合redis,并基于Lettuce的实现。

  • pom.xml
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.xiaodx.redisson</groupId>
    <artifactId>redisson-demo</artifactId>
    <version>1.0.0</version>

    <name>redisson-demo</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <!--spring-boot-starter-parent的版本号[2.2.0.RELEASE]要和[Hoxton.RELEASE]的版本对应 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.3.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.13.3</version>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

    </dependencies>


</project> 


  • 配置
package com.xiaodx.redisson.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
@EnableAutoConfiguration
public class AppConfig {


    /**
     * Spring data 提供了RedisTemplate模板
     * 模板封装了redis连接池管理的逻辑,业务代码不需要关心获取\释放连接逻辑;
     * spring redis 同时支持Jedis 客户端操作;
     *
     */
    @Bean(name="redisTemplate")
    public RedisTemplate<String,Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory){
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(lettuceConnectionFactory);

        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        //在使用注解@Bean返回RedisTemplate时,同时配置hashkey与hashvalue的序列化方式。
        //key序列化方式采用String
        template.setKeySerializer(stringRedisSerializer);
        //value序列化方式采用JACKSON
        template.setValueSerializer(jackson2JsonRedisSerializer);
        //hash的key序列化方式采用String
        template.setHashKeySerializer(stringRedisSerializer);
        //hash的value序列化方式采用JACKSON
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}

  • main方法
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
//        RedisTemplate<String, Object> redisTemplate = applicationContext.getBean("redisTemplate",RedisTemplate.class);
        RedisTemplate<String, Object> redisTemplate = applicationContext.getBean(RedisTemplate.class);
        System.err.println(redisTemplate);
    }
  • 遇到问题
Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.springframework.data.redis.core.RedisTemplate' available: expected single matching bean but found 2: redisTemplate,stringRedisTemplate
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1200)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveBean(DefaultListableBeanFactory.java:420)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:350)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:343)
	at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1127)
	at com.xiaodx.redisson.SetNxDemo.main(SetNxDemo.java:13)
  • 解决思路

根据springboot的自动装配方式,很容易联想到是否redis自代的autoconfig被执行了,于是找到spring-boot-autoconfigration中的类:RedisAutoConfiguration,从以下源码中可以看出,如果用户没有配置名为redisTemplate的bean时,该类会创建一个这样的类,同时还会创建一个StringRedisTemplate的bean,找到这个类的源码,发现这个类继承自RedisTemplate,到此,上面报错原因找到:springboot实例化了RedisTemplate的两个Bean,在使用时不能直接通过getBean(RedisTemplate.class)的方法获取(改成getBean("redisTemplate",RedisTemplate.class)问题即可解决)。

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@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;
	}

}


全部评论: 0

    我有话说: