Allow application to extends those configurations mitigate gh-27834

for example I have two redis services, the default one is @Primary, the global one must be injected with prefix global in @Qualifier

@Primary
@Component
@ConfigurationProperties(prefix = "spring.redis")
public class DefaultRedisProperties extends RedisProperties {

}

@Configuration(proxyBeanMethods = false)
public class DefaultConnectionConfiguration extends LettuceConnectionConfiguration {

    DefaultConnectionConfiguration(RedisProperties properties,
            ObjectProvider<RedisSentinelConfiguration> sentinelConfigurationProvider,
            ObjectProvider<RedisClusterConfiguration> clusterConfigurationProvider) {
        super(properties, sentinelConfigurationProvider, clusterConfigurationProvider);
    }

    @Primary
    @Bean(destroyMethod = "shutdown")
    public DefaultClientResources lettuceClientResources() {
        return super.lettuceClientResources();
    }

    @Primary
    @Bean
    public LettuceConnectionFactory redisConnectionFactory(
            ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers,
            ClientResources globalLettuceClientResources) {
        return super.redisConnectionFactory(builderCustomizers, globalLettuceClientResources);
    }

}

@Configuration(proxyBeanMethods = false)
public class DefaultRedisConfiguration {

    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        return new StringRedisTemplate(redisConnectionFactory);
    }

}

@Component
@ConfigurationProperties(prefix = "global.redis")
public class GlobalRedisProperties extends RedisProperties {

}

@Configuration(proxyBeanMethods = false)
public class GlobalConnectionConfiguration extends LettuceConnectionConfiguration {

    GlobalConnectionConfiguration(GlobalRedisProperties properties,
            ObjectProvider<RedisSentinelConfiguration> sentinelConfigurationProvider,
            ObjectProvider<RedisClusterConfiguration> clusterConfigurationProvider) {
        super(properties, sentinelConfigurationProvider, clusterConfigurationProvider);
    }

    @Bean(destroyMethod = "shutdown")
    DefaultClientResources globalLettuceClientResources() {
        return super.lettuceClientResources();
    }

    @Bean
    LettuceConnectionFactory globalRedisConnectionFactory(
            ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers,
            @Qualifier("globalLettuceClientResources") ClientResources globalLettuceClientResources) {
        return super.redisConnectionFactory(builderCustomizers, globalLettuceClientResources);
    }

}

@Configuration(proxyBeanMethods = false)
public class GlobalRedisConfiguration {

    @Bean
    public RedisTemplate<Object, Object> globalRedisTemplate(
            @Qualifier("globalRedisConnectionFactory") RedisConnectionFactory globalRedisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(globalRedisConnectionFactory);
        return template;
    }

    @Bean
    public StringRedisTemplate globalStringRedisTemplate(
            @Qualifier("globalRedisConnectionFactory") RedisConnectionFactory globalRedisConnectionFactory) {
        return new StringRedisTemplate(globalRedisConnectionFactory);
    }

}

Comment From: philwebb

We discussed this today on our team call and agreed that we'd rather keep those configurations package-private. You should duplicate the appropriate @Bean methods in your own @Configuration for complex setups.