若文章对你有帮助请点个👍👍👍, 表示对我的鼓励, 非常感谢 ❤️❤️❤️
背景
SpringBoot中使用Redis组件, 但是Redis设置了密码, 而明文密码不允许出现在配置文件中, 并且需要将明文按照公司的规定加密,最后使用时再按照公司的要求解密.
难点
SpringBoot无法自动解密用户配置的密文. 需要使用第三方加密, 比如大名鼎鼎的jasypt. 而这里不适合使用jasypt, 因为最好使用公司自己的加密策略.
解决思路
- 理解SpringBoot加载Bean的原理
- 将密文按照用户自定义的方式解密
理解加载Bean原理
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
首先理解 ConditionalOnMissingBean
的理解, 只有 RedisTemplate 类型的Bean缺失的时候才会创建该Bean. 但是创建RedisTemplate比较简单,从注入的RedisConnectionFactory
入手.
从上图看出,RedisConnectionFactory的继承类共有两个,在配置Redis配置的时候, 如果采用Lettuce,则会创建相应的Bean, 并且注入的也是该Bean. 而我配置的是Lettuce, 所以最后注入的是 LettuceConnectionFactory
.
接下来是寻找 LettuceConnectionFactory
Bean对象在什么地方被加载. 查询到是在 LettuceConnectionConfiguration
被创建. 代码如下, 并且也用 ConditionalOnMissingBean
修饰了, 这里就不赘述了.
// LettuceConnectionConfiguration.java
@Bean
@ConditionalOnMissingBean(RedisConnectionFactory.class)
public LettuceConnectionFactory redisConnectionFactory(ClientResources clientResources)
throws UnknownHostException {
LettuceClientConfiguration clientConfig = getLettuceClientConfiguration(clientResources,
this.properties.getLettuce().getPool());
return createLettuceConnectionFactory(clientConfig);
}
创建用户自定义的Bean
@Configuration
public class RedisConfig {
// SpringBoot 中Redis的配置
@Autowired
RedisProperties redisProperties;
//
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
List<RedisNode> nodesList = redisProperties.getCluster().getNodes().stream().map(e -> {
String[] hostAndPort = e.split(":");
return new RedisNode(hostAndPort[0], Integer.valueOf(hostAndPort[1]));
}
).collect(Collectors.toList());
RedisProperties.Lettuce lettuce = redisProperties.getLettuce();
RedisClusterConfiguration redisBaseConfig = new RedisClusterConfiguration();
redisBaseConfig.setClusterNodes(nodesList);
// 密码配置的关键地方
if (redisProperties.getPassword() != null && StringUtils.isNotEmpty(redisProperties.getPassword())) {
redisBaseConfig.setPassword(KeyCenterUtil.decrypt(redisProperties.getPassword()));
}
LettucePoolingClientConfiguration lettuceConfig = LettucePoolingClientConfiguration
.builder()
.poolConfig(getPoolConfig(lettuce.getPool()))
.shutdownTimeout(lettuce.getShutdownTimeout())
.build();
return new LettuceConnectionFactory(redisBaseConfig, lettuceConfig);
}
// 分析源码后, 将源码中的提取出来自己使用. 对方不允许用户使用.
private GenericObjectPoolConfig<?> getPoolConfig(RedisProperties.Pool properties) {
GenericObjectPoolConfig<?> config = new GenericObjectPoolConfig<>();
config.setMaxTotal(properties.getMaxActive());
config.setMaxIdle(properties.getMaxIdle());
config.setMinIdle(properties.getMinIdle());
if (properties.getTimeBetweenEvictionRuns() != null) {
config.setTimeBetweenEvictionRunsMillis(properties.getTimeBetweenEvictionRuns().toMillis());
}
if (properties.getMaxWait() != null) {
config.setMaxWaitMillis(properties.getMaxWait().toMillis());
}
return config;
}
}