使用Spring Session与Redis时@ConfigurationProperties自动注入失败
解决Spring Session集成Redis时自定义配置属性注入为空的问题
我来帮你分析下这个空指针问题的根源,以及对应的解决办法:
问题根源
你遇到的NullPointerException是因为类成员变量的初始化时机早于Spring的依赖注入时机。在RedisHttpSessionConfig类中,sentinelConfig是一个类级别的成员变量,它会在类的构造函数执行时就被初始化。但Spring的@Autowired字段注入是在Bean实例化(构造函数执行完成)之后才进行的,这时候redisSentinelProperties还没被注入,自然就是null,调用它的方法就会抛出空指针异常。
而在没有引入Spring Session的时候,你的配置类初始化逻辑没有在构造阶段就依赖这个注入的属性,所以不会触发这个问题。
解决方案
这里提供几种可行的修改方式,你可以根据自己的习惯选择:
方案1:将sentinelConfig的初始化移到connectionFactory Bean方法内
把哨兵配置的创建逻辑放到connectionFactory()方法里,这样Spring在创建这个Bean的时候,已经完成了redisSentinelProperties的注入:
@Configuration @EnableRedisHttpSession @EnableWebSecurity public class RedisHttpSessionConfig { @Autowired private RedisSentinelProperties redisSentinelProperties; LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder() .readFrom(SLAVE_PREFERRED) .build(); @Bean public LettuceConnectionFactory connectionFactory() { // 在这里初始化哨兵配置,此时redisSentinelProperties已经被注入 Set<String> nodes = redisSentinelProperties.getSentinel().getNodes().stream().collect(Collectors.toSet()); RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration(redisSentinelProperties.getMasterName(), nodes); return new LettuceConnectionFactory(sentinelConfig, clientConfig); } }
方案2:使用构造函数注入替代字段注入
构造函数注入是Spring推荐的注入方式,它能确保在Bean实例化时就拿到依赖的对象,避免空指针:
@Configuration @EnableRedisHttpSession @EnableWebSecurity public class RedisHttpSessionConfig { private final RedisSentinelProperties redisSentinelProperties; private final RedisSentinelConfiguration sentinelConfig; LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder() .readFrom(SLAVE_PREFERRED) .build(); // 构造函数注入,Spring会自动传入RedisSentinelProperties实例 public RedisHttpSessionConfig(RedisSentinelProperties redisSentinelProperties) { this.redisSentinelProperties = redisSentinelProperties; // 此时可以安全地初始化sentinelConfig Set<String> nodes = redisSentinelProperties.getSentinel().getNodes().stream().collect(Collectors.toSet()); this.sentinelConfig = new RedisSentinelConfiguration(redisSentinelProperties.getMasterName(), nodes); } @Bean public LettuceConnectionFactory connectionFactory() { return new LettuceConnectionFactory(sentinelConfig, clientConfig); } }
方案3:将sentinelConfig声明为@Bean
把哨兵配置也定义成一个Spring Bean,Spring会自动处理依赖顺序,确保redisSentinelProperties注入完成后再创建这个Bean:
@Configuration @EnableRedisHttpSession @EnableWebSecurity public class RedisHttpSessionConfig { @Autowired private RedisSentinelProperties redisSentinelProperties; LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder() .readFrom(SLAVE_PREFERRED) .build(); @Bean public RedisSentinelConfiguration sentinelConfig() { Set<String> nodes = redisSentinelProperties.getSentinel().getNodes().stream().collect(Collectors.toSet()); return new RedisSentinelConfiguration(redisSentinelProperties.getMasterName(), nodes); } @Bean public LettuceConnectionFactory connectionFactory(RedisSentinelConfiguration sentinelConfig) { return new LettuceConnectionFactory(sentinelConfig, clientConfig); } }
验证修改
修改完成后,重新启动应用,应该就能正常获取到自定义的Redis哨兵配置,不再抛出空指针异常了。
内容的提问来源于stack exchange,提问作者Nandeesh
相关产品推荐
相关产品推荐

