redisson-spring-boot-starter 自动化配置源码解析

版本

redisson-spring-boot-starter:3.25.2

此starter会自动注册RedissonClient Bean
并可通过注册RedissonAutoConfigurationCustomizer Bean实现配置自定义

 @Bean
 RedissonAutoConfigurationCustomizer jdkCodecCustomizer() {
   
     return configuration->{
   
         // 使用JDK序列化器
         configuration.setCodec(new SerializationCodec());
     };
 }

源码

spring-boot:2.7以上
org.redisson.spring.starter.RedissonAutoConfigurationV2

@AutoConfiguration(before = RedisAutoConfiguration.class)
@ConditionalOnClass({
   Redisson.class, RedisOperations.class})
@EnableConfigurationProperties({
   RedissonProperties.class, RedisProperties.class}) // 启用spring.data.redis,spring.redisson配置属性
public class RedissonAutoConfigurationV2 extends RedissonAutoConfiguration {
   
}

spring-boot:2.6以下
org.redisson.spring.starter.RedissonAutoConfiguration

@Configuration
@ConditionalOnClass({
   Redisson.class, RedisOperations.class})
// 防止spring-boot:2.7以上版本时跟RedissonAutoConfigurationV2冲突
@ConditionalOnMissingClass("org.springframework.boot.autoconfigure.AutoConfiguration") 
@AutoConfigureBefore(RedisAutoConfiguration.class)
@EnableConfigurationProperties({
   RedissonProperties.class, RedisProperties.class})
public class RedissonAutoConfiguration {
   
	...
	// 注册RedissonClient 
	@Bean(destroyMethod = "shutdown")
    @ConditionalOnMissingBean(RedissonClient.class)
    public RedissonClient redisson() throws IOException {
   
        Config config;
        Method clusterMethod = ReflectionUtils.findMethod(RedisProperties.class, "getCluster");
        Method usernameMethod = ReflectionUtils.findMethod(RedisProperties.class, "getUsername");
        Method timeoutMethod = ReflectionUtils.findMethod(RedisProperties.class, "getTimeout");
        Method connectTimeoutMethod = ReflectionUtils.findMethod(RedisProperties.class, "getConnectTimeout");
        Method clientNameMethod = ReflectionUtils.findMethod(RedisProperties.class, "getClientName");

        Object timeoutValue = ReflectionUtils.invokeMethod(timeoutMethod, redisProperties);
        String prefix = getPrefix();

        String username = null;
        int database = redisProperties.getDatabase();
        String password = redisProperties.getPassword();
        boolean isSentinel = false;
        boolean isCluster = false;
        // 如果存在redis连接详细配置,则从详细配置中获取用户名,密码,哨兵模式标识,集群模式标识
        if (hasConnectionDetails()) {
   
            ObjectProvider<RedisConnectionDetails> provider = ctx.getBeanProvider(RedisConnectionDetails.class);
            RedisConnectionDetails b = provider.getIfAvailable();
            if (b != null) {
   
                password = b.getPassword();
                username = b.getUsername();

                if (b.getSentinel() != null) {
   
                    isSentinel = true;
                }
                if (b.getCluster() != null) {
   
                    isCluster = true;
                }
            }
        }
		// 获取redis配置中的超时时间
        Integer timeout = null;
        if (timeoutValue instanceof Duration) {
   
            timeout = (int) ((Duration) timeoutValue).toMillis();
        } else if (timeoutValue != null){
   
            timeout = (Integer)timeoutValue;
        }
		// 获取redis配置中的连接超时时间
        Integer connectTimeout = null;
        if (connectTimeoutMethod != null) {
   
            Object connectTimeoutValue = ReflectionUtils.invokeMethod(connectTimeoutMethod, redisProperties);
            if (connectTimeoutValue != null) {
   
                connectTimeout = (int) ((Duration) connectTimeoutValue).toMillis();
            }
        } else {
   
            connectTimeout = timeout;
        }
		// 获取redis配置中的客户端名称
        String clientName = null;
        if (clientNameMethod != null) {
   
            clientName = (String) ReflectionUtils.invokeMethod(clientNameMethod, redisProperties);
        }
		// 获取redis配置中的用户名
        if (usernameMethod != null) {
   
            username = (String) ReflectionUtils.invokeMethod(usernameMethod, redisProperties);
        }
		if (redissonProperties.getConfig() != null) {
   
            // 如果存在redisson配置(在application.yml中以字符串形式配置)
        	try {
   
            	// 尝试解析yml格式配置字符串
                config = Config.fromYAML(redissonProperties.getConfig());
            } catch (IOException e) {
   
                try {
   
                	// 尝试解析json格式配置字符串
                    config = Config.fromJSON(redissonProperties.getConfig());
                } catch (IOException e1) {
   
                    e1.addSuppressed(e);
                    throw new IllegalArgumentException("Can't parse config", e1);
                }
            }
        } else if (redissonProperties.getFile() != null) {
   
        	// 如果存在redisson配置文件(yml或json)
            try {
   
                InputStream is = getConfigStream();
                config = Config.fromYAML(is);
            } catch (IOException e) {
   
                // trying next format
                try {
   
                    InputStream is = getConfigStream();
                    config = Config.fromJSON(is);
                } catch (IOException e1) {
   
                    e1.addSuppressed(e);
                    throw new IllegalArgumentException("Can't parse config", e1);
                }
            }
        } else if (redisProperties.getSentinel() != null || isSentinel) {
   
        	// 连接哨兵模式集群
            String[] nodes = {
   };
            String sentinelMaster = null;

            if (redisProperties.getSentinel() != null) {
   
                Method nodesMethod = ReflectionUtils.findMethod(Sentinel.class, "getNodes");
                Object nodesValue = ReflectionUtils.invokeMethod(nodesMethod, redisProperties.getSentinel());
                if (nodesValue instanceof String) {
   
                    nodes = convert(prefix, Arrays.asList(((String)nodesValue).split(",")));
                } else {
   
                    nodes = convert(prefix, (List<String>)nodesValue);
                }
                sentinelMaster = redisProperties.getSentinel().getMaster();
            }


            String sentinelUsername = null;
            String sentinelPassword = null;
            if (hasConnectionDetails()) {
   
                ObjectProvider<RedisConnectionDetails> provider = ctx.getBeanProvider(RedisConnectionDetails.class);
                RedisConnectionDetails b = provider.getIfAvailable();
                if (b != null && b.getSentinel() != null) {
   
                    database = b.getSentinel().getDatabase();
                    sentinelMaster = b.getSentinel().getMaster();
                    nodes = convertNodes(prefix, (List<Object>) (Object) b.getSentinel().getNodes());
                    sentinelUsername = b.getSentinel().getUsername();
                    sentinelPassword = b.getSentinel().getPassword();
                }
            }

            config = new Config();
            SentinelServersConfig c = config.useSentinelServers()
                    .setMasterName(sentinelMaster)
                    .addSentinelAddress(nodes)
                    .setSentinelPassword(sentinelPassword)
                    .setSentinelUsername(sentinelUsername)
                    .setDatabase(database)
                    .setUsername(username)
                    .setPassword(password)
                    .setClientName(clientName);
            if (connectTimeout != null) {
   
                c.setConnectTimeout(connectTimeout);
            }
            if (connectTimeoutMethod != null && timeout != null) {
   
                c.setTimeout(timeout);
            }
            initSSL(c);
        } else if ((clusterMethod != null && ReflectionUtils.invokeMethod(clusterMethod, redisProperties) != null)
                    || isCluster) {
   
			// 连接分片集群
            String[] nodes = {
   };
            if (clusterMethod != null && ReflectionUtils.invokeMethod(clusterMethod, redisProperties) != null) {
   
                Object clusterObject = ReflectionUtils.invokeMethod(clusterMethod, redisProperties);
                Method nodesMethod = ReflectionUtils.findMethod(clusterObject.getClass(), "getNodes");
                List<String> nodesObject = (List) ReflectionUtils.invokeMethod(nodesMethod, clusterObject);

                nodes = convert(prefix, nodesObject);
            }

            if (hasConnectionDetails()) {
   
                ObjectProvider<RedisConnectionDetails> provider = ctx.getBeanProvider(RedisConnectionDetails.class);
                RedisConnectionDetails b = provider.getIfAvailable();
                if (b != null && b.getCluster() != null) {
   
                    nodes = convertNodes(prefix, (List<Object>) (Object) b.getCluster().getNodes());
                }
            }

            config = new Config();
            ClusterServersConfig c = config.useClusterServers()
                    .addNodeAddress(nodes)
                    .setUsername(username)
                    .setPassword(password)
                    .setClientName(clientName);
            if (connectTimeout != null) {
   
                c.setConnectTimeout(connectTimeout);
            }
            if (connectTimeoutMethod != null && timeout != null) {
   
                c.setTimeout(timeout);
            }
            initSSL(c);
        } else {
   
        	// 连接单实例
            config = new Config();

            String singleAddr = prefix + redisProperties.getHost() + ":" + redisProperties.getPort();

            if (hasConnectionDetails()) {
   
                ObjectProvider<RedisConnectionDetails> provider = ctx.getBeanProvider(RedisConnectionDetails.class);
                RedisConnectionDetails b = provider.getIfAvailable();
                if (b != null && b.getStandalone() != null) {
   
                    database = b.getStandalone().getDatabase();
                    singleAddr = prefix + b.getStandalone().getHost() + ":" + b.getStandalone().getPort();
                }
            }

            SingleServerConfig c = config.useSingleServer()
                    .setAddress(singleAddr)
                    .setDatabase(database)
                    .setUsername(username)
                    .setPassword(password)
                    .setClientName(clientName);
            if (connectTimeout != null) {
   
                c.setConnectTimeout(connectTimeout);
            }
            if (connectTimeoutMethod != null && timeout != null) {
   
                c.setTimeout(timeout);
            }
            initSSL(c);
        }
        // 应用自定义配置bean
        if (redissonAutoConfigurationCustomizers != null) {
   
            for (RedissonAutoConfigurationCustomizer customizer : redissonAutoConfigurationCustomizers) {
   
                customizer.customize(config);
            }
        }
        return Redisson.create(config);
    }

    private void initSSL(BaseConfig<?> config) {
   
        Method getSSLMethod = ReflectionUtils.findMethod(RedisProperties.class, "getSsl");
        if (getSSLMethod == null) {
   
            return;
        }

        RedisProperties.Ssl ssl = redisProperties.getSsl();
        if (ssl.getBundle() == null) {
   
            return;
        }

        ObjectProvider<SslBundles> provider = ctx.getBeanProvider(SslBundles.class);
        SslBundles bundles = provider.getIfAvailable();
        if (bundles == null) {
   
            return;
        }
        SslBundle b = bundles.getBundle(ssl.getBundle());
        if (b == null) {
   
            return;
        }
        config.setSslCiphers(b.getOptions().getCiphers());
        config.setSslProtocols(b.getOptions().getEnabledProtocols());
        config.setSslTrustManagerFactory(b.getManagers().getTrustManagerFactory());
        config.setSslKeyManagerFactory(b.getManagers().getKeyManagerFactory());
    }
}

相关推荐

  1. redisson-spring-boot-starter 自动化配置

    2024-01-20 14:12:03       29 阅读
  2. spring oauth2 authorization server 配置

    2024-01-20 14:12:03       35 阅读
  3. SpringBoot-SpringBoot自动配置底层

    2024-01-20 14:12:03       31 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-20 14:12:03       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-20 14:12:03       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-20 14:12:03       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-20 14:12:03       18 阅读

热门阅读

  1. Android13预装APP到data分区

    2024-01-20 14:12:03       40 阅读
  2. 【issue-halcon例程学习】ball.hdev

    2024-01-20 14:12:03       28 阅读
  3. 动态sql,关联查询

    2024-01-20 14:12:03       31 阅读
  4. Webpack打包vue项目

    2024-01-20 14:12:03       36 阅读
  5. 173. 二叉搜索树迭代器

    2024-01-20 14:12:03       33 阅读