springboot控制是否注册redis

一、博客背景

最近项目中有使用到redis做缓存队列,但是还提供了其他的缓存方式,所以redis需要做成可配置的,所以在这里记录下项目中的配置情况。

二、代码

将redis的所有相关文件放在一个application-redis.properties配置文件中,当需要使用该配置的时候在application.properties中的配置项中加上spring.profiles.active=redis

################### Redis配置#####################
#第一个redis集群的配置,用于基础数据的缓存
redis.useRedisModel=1
#集群模式连接
redis.cluster.nodes=192.169.1.26:7001,192.169.1.26:7002,192.169.1.26:7003,192.169.1.26:7004,192.169.1.26:7005,192.169.1.26:7006
#redis.cluster.nodes=192.169.1.196:7001,192.169.1.196:7002,192.169.1.196:7003,192.169.1.196:7004,192.169.1.196:7005,192.169.1.196:7006
#重试连接次数
redis.cluster.max-redirects=3
#最大连接数
redis.pool.max-active=50
#最大等待超时时间
redis.pool.max-wait=5
#最大空闲数
redis.pool.max-idle=50
#最小空闲数
redis.pool.min-idle=0
#超时时间
redis.timeout=50000
#使用的数据库
redis.database=0
#redis连接密码需要时放开
#redis.password=ENC(5M5nrpgKIQBkqEcldhbK6A==)
#redis.host=127.0.0.1
#redis.port=6379

条件控制类

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

/**
 * redis相关bean是否注册条件类
 */
public class RedisCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {
        //获取当前环境信息
        Environment environment = conditionContext.getEnvironment();
        //是否使用redis
        String property = environment.getProperty("redis.useRedisModel");
        return property != null && Integer.parseInt(property) == 0;
    }
}

redis配置类

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.MapPropertySource;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;


@Configuration
public class RedisConfig {
    /**最大活跃数**/
    @Value("${redis.pool.max-active:8}")
    private int maxActive;

    /**最大等待数**/
    @Value("${redis.pool.max-wait:-1}")
    private int maxWait;

    /**最大核心线程数**/
    @Value("${redis.pool.max-idle:8}")
    private int maxIdle;

    /**最小核心线程数**/
    @Value("${redis.pool.min-idle:0}")
    private int minIdle;

    /**redis连接的超时时长**/
    @Value("${redis.timeout:100}")
    private int timeOut;

    /**redis连接的库**/
    @Value("${redis.database:0}")
    private int database;

    /**节点配置**/
    @Value("${redis.cluster.nodes:#{null}}")
    private String nodes;

    /**最大连接转移数**/
    @Value("${redis.cluster.max-redirects:3}")
    private int maxRedirects;

    /**单节点情况下redis的ip**/
    @Value("${redis.host:#{null}}")
    private String host;

    /**单节点情况下redis的端口**/
    @Value("${redis.port:#{null}}")
    private Integer port;

    /**redis的连接密码**/
    @Value("${redis.password:#{null}}")
    private String password;
    /**
     * 创建redisTemplate
     * 所有序列化k/v都会默认使用{@link JdkSerializationRedisSerializer}
     * 默认的序列化类用使用byte数组进行存储, 在使用redis可视化客户端看到都是乱码不直观
     * 使用StringRedisSerializer序列化Key,  Jackson2JsonRedisSerializer序列化值, 可以观察到对象结构层次
     *
     * @return redisTemplate
     */
    @Bean
    @Qualifier("redisTemplate")
    @Conditional(value = RedisCondition.class)
    public <K, V> RedisTemplate<K, V> redisTemplate() {
        Jackson2JsonRedisSerializer<Object> valueSerializer = jackson2JsonRedisSerializer();
        StringRedisSerializer keySerializer = new StringRedisSerializer();
        RedisTemplate<K, V> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(connectionFactory());
        redisTemplate.setKeySerializer(keySerializer);
        redisTemplate.setValueSerializer(valueSerializer);
        redisTemplate.setHashKeySerializer(keySerializer);
        redisTemplate.setHashValueSerializer(valueSerializer);
        return redisTemplate;
    }

    /**
     * 定义序列化类
     *
     * @return 序列化工具
     */
    private Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer() {
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().build();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        return jackson2JsonRedisSerializer;
    }

    /**
     * 连接配置
     * @return redis连接工厂
     */
    @Primary
    @Bean
    @Conditional(value = RedisCondition.class)
    public RedisConnectionFactory  connectionFactory() {
        Map<String, Object> source = new HashMap<>(4);
        RedisClusterConfiguration redisClusterConfiguration;
        RedisStandaloneConfiguration redisStandaloneConfiguration;
        //连接池配置
        GenericObjectPoolConfig genericObjectPoolConfig =
                new GenericObjectPoolConfig();
        genericObjectPoolConfig.setMaxTotal(maxActive);
        genericObjectPoolConfig.setMaxWaitMillis(maxWait);
        genericObjectPoolConfig.setMaxIdle(maxIdle);
        genericObjectPoolConfig.setMinIdle(minIdle);

        //redis客户端配置
        LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder
                builder =  LettucePoolingClientConfiguration.builder().
                commandTimeout(Duration.ofSeconds(timeOut));
        builder.poolConfig(genericObjectPoolConfig);
        LettuceClientConfiguration lettuceClientConfiguration = builder.build();

        //集群模式
        if(StrUtil.isNotEmpty(nodes)){
            source.put("spring.redis.cluster.nodes", nodes);
            source.put("spring.redis.cluster.max-redirects", maxRedirects);
            redisClusterConfiguration = new RedisClusterConfiguration(new MapPropertySource("RedisClusterConfiguration", source));
            if(!StrUtil.isEmpty(password)){
                redisClusterConfiguration.setPassword(password);
            }
            return new LettuceConnectionFactory(redisClusterConfiguration,lettuceClientConfiguration);
        }else{
            //单机模式
            redisStandaloneConfiguration = new RedisStandaloneConfiguration(host,port);
            redisStandaloneConfiguration.setDatabase(database);
            if(!StrUtil.isEmpty(password)){
                redisStandaloneConfiguration.setPassword(password);
            }
            return new LettuceConnectionFactory(redisStandaloneConfiguration,lettuceClientConfiguration);

        }
    }
}

三、代码讲解

在代码里我们定义了一个条件控制类RedisCondition,由这个类来控制是否注入redis的相关bean,换成具体的业务逻辑就是由

String property = environment.getProperty("redis.useRedisModel");

读取配置文件是否使用redis来控制

然后我们可以看到在redis的配置类里,我们可以看到无论是redis的连接工厂还是redistemplate的注解方法上都有加

@Conditional(value = RedisCondition.class)

这一行配置,即为如果RedisCondition.class的结果是真,则注入这两个bean

四、知识延伸

@Conditional注解

@Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件给容器注册bean。

还有以下等注解

@ConditionalOnBean
@ConditionalOnMissingBean
@ConditionalOnClass
@ConditionalOnMissingClass
@ConditionalOnProperty
@ConditionalOnExpression

具体使用可以自行百度搜索

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值