likes
comments
collection
share

Springboot动态redis 数据源数据库

作者站长头像
站长
· 阅读数 63

1, 准备工作,新建一个一个springboot maven 工程, 这里我们不需要web的依赖,只需要data-redis 的依赖就行的。

2, 代码逻辑

Springboot动态redis 数据源数据库

3, 正式的写代码

大部分的代码都和之前那个老哥文章代码差不多, 这里我只是加上了切换redis 数据库的逻辑。 核心代码 

package com.ducheng.multi.redis;
import org.springframework.beans.factory.DisposableBean;import org.springframework.beans.factory.InitializingBean;import org.springframework.dao.DataAccessException;import org.springframework.data.redis.connection.*;import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;import org.springframework.util.ObjectUtils;import java.util.Map;
public class MultiRedisConnectionFactory        implements InitializingBean, DisposableBean, RedisConnectionFactory, ReactiveRedisConnectionFactory {    private final Map<String, LettuceConnectionFactory> connectionFactoryMap;
    /**    
    * * 当前redis的名字    
    * */    
    private static final ThreadLocal<String> currentRedisName = new ThreadLocal<>();
    /**     
    *  当前redis的db数据库    
    */   
    private static final ThreadLocal<Integer> currentRedisDb = new ThreadLocal<>();

    public MultiRedisConnectionFactory(Map<String, LettuceConnectionFactory> connectionFactoryMap) {       
    this.connectionFactoryMap = connectionFactoryMap;   
    }
    public void setCurrentRedis(String currentRedisName) {       
    if (!connectionFactoryMap.containsKey(currentRedisName)) { 
          throw new RuntimeException("invalid currentRedis: " + currentRedisName + ",  it does not exists in configuration");       
    }       
    MultiRedisConnectionFactory.currentRedisName.set(currentRedisName);   
    }
    
    
    /**     * 选择连接和数据库    
    * @param currentRedisName    
    * @param db     */    
    public void setCurrentRedis(String currentRedisName,Integer db) {        
    if (!connectionFactoryMap.containsKey(currentRedisName)) {            
    throw new RuntimeException("invalid currentRedis: " + currentRedisName + ",  it does not exists in configuration");       
    }        
    MultiRedisConnectionFactory.currentRedisName.set(currentRedisName);         MultiRedisConnectionFactory.currentRedisDb.set(db);    
    }

    @Override    
    public void destroy() throws Exception {
    connectionFactoryMap.values().forEach(LettuceConnectionFactory::destroy);        }
    @Override    
    public void afterPropertiesSet() throws Exception {  
    connectionFactoryMap.values().forEach(LettuceConnectionFactory::afterPropertiesSet);   
    }
    
    private LettuceConnectionFactory currentLettuceConnectionFactory() { 
    String currentRedisName = MultiRedisConnectionFactory.currentRedisName.get();       
           if (!ObjectUtils.isEmpty(currentRedisName)) {  
           MultiRedisConnectionFactory.currentRedisName.remove();           
           return connectionFactoryMap.get(currentRedisName);       
           }      
         return connectionFactoryMap.get(MultiRedisProperties.DEFAULT);    
    }
    
    @Override   
    public ReactiveRedisConnection getReactiveConnection() { 
    
    return currentLettuceConnectionFactory().getReactiveConnection();    
    
    }
    
    
    @Override    
    public ReactiveRedisClusterConnection getReactiveClusterConnection() {        
    return currentLettuceConnectionFactory().getReactiveClusterConnection();    
    
    }
    @Override   
    
    public RedisConnection getConnection() {   
    // 这里就是切换数据库的地方        
    Integer currentRedisDb = MultiRedisConnectionFactory.currentRedisDb.get();       
    if (!ObjectUtils.isEmpty(currentRedisDb)) {
    
    LettuceConnectionFactory lettuceConnectionFactory =   currentLettuceConnectionFactory(); 
    
    lettuceConnectionFactory.setShareNativeConnection(false); 
    
    RedisConnection connection = lettuceConnectionFactory.getConnection();   
    
    connection.select(currentRedisDb);
    
    return connection;       
    }       
    return   currentLettuceConnectionFactory().getConnection();    
    }
    @Override    
    public RedisClusterConnection getClusterConnection() {
    
    return currentLettuceConnectionFactory().getClusterConnection();
    
    }
    
    @Override    
    public boolean getConvertPipelineAndTxResults() {        
    
    return currentLettuceConnectionFactory().getConvertPipelineAndTxResults();    }
    @Override    
    public RedisSentinelConnection getSentinelConnection() {
    
    return currentLettuceConnectionFactory().getSentinelConnection();    
    }
    
    @Override    
    public DataAccessException translateExceptionIfPossible(RuntimeException ex) {        
    return currentLettuceConnectionFactory().translateExceptionIfPossible(ex);    
    }
}

根据条件注解注入redis 数据库的工厂 核心代码 

package org.springframework.boot.autoconfigure.data.redis;

import com.ducheng.multi.redis.MultiRedisConnectionFactory;import com.ducheng.multi.redis.MultiRedisProperties;import io.lettuce.core.resource.ClientResources;import org.springframework.beans.factory.ObjectProvider;import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.data.redis.connection.RedisClusterConfiguration;import org.springframework.data.redis.connection.RedisSentinelConfiguration;import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import java.util.HashMap;import java.util.Map;
@ConditionalOnProperty(prefix = "spring.redis", value = "enable-multi", matchIfMissing = false)@Configuration(proxyBeanMethods = false)public class RedisCustomizedConfiguration {
    /**  * @param builderCustomizers    
    * @param clientResources     
    * @param multiRedisProperties    
    * @return     * @see org.springframework.boot.autoconfigure.data.redis.LettuceConnectionConfiguration     */    
    @Bean    
    public MultiRedisConnectionFactory  multiRedisConnectionFactory(     ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers,            ClientResources clientResources,            
    MultiRedisProperties multiRedisProperties,           
    ObjectProvider<RedisSentinelConfiguration> sentinelConfigurationProvider,            ObjectProvider<RedisClusterConfiguration> clusterConfigurationProvider)
    { 
    Map<String, LettuceConnectionFactory> connectionFactoryMap = new HashMap<>(); 
    
    Map<String, RedisProperties> multi = multiRedisProperties.getMulti();  
    multi.forEach((k, v) -> {            
    LettuceConnectionConfiguration lettuceConnectionConfiguration = new LettuceConnectionConfiguration(                    v,                    sentinelConfigurationProvider,                    clusterConfigurationProvider            );           
    LettuceConnectionFactory lettuceConnectionFactory = lettuceConnectionConfiguration.redisConnectionFactory(builderCustomizers, clientResources);           
    connectionFactoryMap.put(k, lettuceConnectionFactory);       
    });        
    return new MultiRedisConnectionFactory(connectionFactoryMap);   
    }
}

redis 的配置类

@ConfigurationProperties(prefix = "spring.redis")public class MultiRedisProperties {   
/**     * 默认连接必须配置,配置 key 为 default     */    
public static final String DEFAULT = "default";
    private boolean enableMulti = false;

    private Map<String, RedisProperties> multi;
    public boolean isEnableMulti() {       
    return enableMulti;    
    }
    public void setEnableMulti(boolean enableMulti) {        
    this.enableMulti = enableMulti;    
    }
    public Map<String, RedisProperties> getMulti() {       
    return multi;    
    }
    public void setMulti(Map<String, RedisProperties> multi) {        
    this.multi = multi;    
    }
    public MultiRedisProperties() {}
    }

代码测试:

配置文件配置多数据源:

spring.redis.enable-multi=true
spring.redis.multi.default.host=xxxxxxxx
spring.redis.multi.default.port=6381
spring.redis.multi.test.host=xxxxxxxx
spring.redis.multi.test.port=6380

配置redisTemplate 

@Bean  
public RedisTemplate<String, Object> template(RedisConnectionFactory factory) {   
// 创建RedisTemplate<String, Object>对象    
RedisTemplate<String, Object> template = new RedisTemplate<>();    
// 配置连接工厂    template.setConnectionFactory(factory);    
// 定义Jackson2JsonRedisSerializer序列化对象
Jackson2JsonRedisSerializer<Object> jacksonSeial = new Jackson2JsonRedisSerializer<>(Object.class);    
ObjectMapper om = new ObjectMapper();    
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public 
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);    
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会报异常   
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); 
jacksonSeial.setObjectMapper(om);    
StringRedisSerializer stringSerial = new StringRedisSerializer();    
// redis key 序列化方式使用stringSerial
template.setKeySerializer(stringSerial);    
// redis value 序列化方式使用jackson    
template.setValueSerializer(jacksonSeial);    
// redis hash key 序列化方式使用stringSerial 
template.setHashKeySerializer(stringSerial);    
// redis hash value 序列化方式使用jackson  
template.setHashValueSerializer(jacksonSeial);    
template.afterPropertiesSet();   
return template; 
}

编写测试代码:

package com.ducheng.multi.redis;
import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.data.redis.connection.RedisConnection;import org.springframework.data.redis.core.RedisTemplate;
@SpringBootTestclass MultiRedisSourceApplicationTests {
 
 @Autowired  RedisTemplate<String, Object> redisTemplate;
  
  @Autowired  MultiRedisConnectionFactory multiRedisConnectionFactory;
  
  @Test  void contextLoads() {    
  // 走默认的数据源   
  redisTemplate.opsForValue().set("k1","v1");    
  // 走test数据源0 库   
  multiRedisConnectionFactory.setCurrentRedis("test",0);   
  // 走test数据源9 库   
  redisTemplate.opsForValue().set("k1","v2"); 
  
  multiRedisConnectionFactory.setCurrentRedis("test",9);
  
  redisTemplate.opsForValue().set("k1","v2");  }
}

最后结果 Springboot动态redis 数据源数据库

Springboot动态redis 数据源数据库

Springboot动态redis 数据源数据库

Springboot动态redis 数据源数据库

完美,自定义注解加上aop 来动态切换,就是定义一个自定义的注解里面包含库名称和db 的名称

然后 就是在aop 的前置拦截器上面,或者注解的值, 然后在用MultiRedisConnectionFactory  来设置数据源和db 。 相关的代码已发布到maven 私服, 使用教程请看 ducheng.github.io/dynamicRedi…

转载自:https://juejin.cn/post/7149472667995734024
评论
请登录