Вот в чем дело
В проекте используется Springboot + spring data redis, но компания оговаривает, что все пароли redis размещаются на хостинге и могут быть получены только удаленно.
Redis с одним экземпляром, используемый в среде разработки, и салат, используемый для пула соединений, реализуются путем копирования кода, автоматически загружаемого Spring Data Redis, в проект.Причину можно увидеть из следующего анализа, ядра конфигурации, связанной со Spring. Классы видны пакету и не могут быть унаследованы и на них нельзя ссылаться извне.
Однако добрые люди, то есть следующие, посчитали, что этого «весна не хватает», поэтому копнули немного глубже, и после некоторого анализа предложили сообществу более актуальный Issue, и он был принят.
Механизм автоподключения Spring Data Redis
существуетorg.springframework.boot.autoconfigure.data.redis
имеютRedisAutoConfiguration
, который проходит@Import
зависит отLettuceConnectionConfiguration
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
LettuceConnectionConfiguration
унаследовано отRedisConnectionConfiguration
, основной код выглядит следующим образом
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisClient.class) // -->①
@ConditionalOnProperty(name = "spring.redis.client-type", havingValue = "lettuce", matchIfMissing = true) // -->②
class LettuceConnectionConfiguration extends RedisConnectionConfiguration {
LettuceConnectionConfiguration(RedisProperties properties,
ObjectProvider<RedisSentinelConfiguration> sentinelConfigurationProvider,
ObjectProvider<RedisClusterConfiguration> clusterConfigurationProvider) {
super(properties, sentinelConfigurationProvider, clusterConfigurationProvider);
}
@Bean
@ConditionalOnMissingBean(RedisConnectionFactory.class) // -->③
LettuceConnectionFactory redisConnectionFactory(
ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers,
ClientResources clientResources) {
LettuceClientConfiguration clientConfig = getLettuceClientConfiguration(builderCustomizers, clientResources,
getProperties().getLettuce().getPool());
return createLettuceConnectionFactory(clientConfig);
}
}
Из этого видно, что условия загрузки Spring для автоматического подключения фабрики соединений Lettuce следующие:
① существуетRedisClient
,lettuce.io
Клиентский класс Redis, который поставляется с
② Конфигурация, используемая в проектеspring.redis.client-type
заlettuce
③ Пока это не определено в коде проектаRedisConnectionFactory
, он будет создан автоматически в соответствии с конфигурационным файломLettuceConnectionFactory
Среди них есть два ключевых момента,
- Конструктор
LettuceConnectionConfiguration
появившийсяRedisProperties
и дваObjectProvider
, а конструктор родительского класса вызывается -
redisConnectionFactory
содержит два важных методаgetLettuceClientConfiguration
а такжеcreateLettuceConnectionFactory
, вgetLettuceClientConfiguration
В основном он касается соответствующей конфигурации пула соединений пула, не вдаваясь в подробности. Вы также можете узнать из следующего анализа,properties
На самом деле этоRedisProperties
, Сфокусируйся наcreateLettuceConnectionFactory
Ниже мы проанализируем эти ключевые моменты один за другим.
конструктор родительского классаRedisConnectionConfiguration
protected RedisConnectionConfiguration(RedisProperties properties,
ObjectProvider<RedisSentinelConfiguration> sentinelConfigurationProvider,
ObjectProvider<RedisClusterConfiguration> clusterConfigurationProvider) {
this.properties = properties;
this.sentinelConfiguration = sentinelConfigurationProvider.getIfAvailable();
this.clusterConfiguration = clusterConfigurationProvider.getIfAvailable();
}
Ключом к пониманию этого кода являетсяObjectProvider
, На самом деле, если вы внимательно посмотрите, вы обнаружите, что код Springboot, особенно конструктор, использует многоObjectProvider
ObjectProvider
оObjectProvider
, можно вкратце рассказать о некоторых улучшениях Spring 4.3
Когда параметр конструктора является одним параметром конструктора, вы можете аннотировать с помощью @Autowired
@Service
public class FooService {
private final FooRepository repository;
public FooService(FooRepository repository) {
this.repository = repository
}
}
Например, приведенный выше код является версией после весны 4.3, не нужно@Autowired
тоже нормально работает.
Также в версии Spring 4.3 неявно внедряются не только свойства параметров одиночной конструкции, но и введение
ObjectProvider
интерфейс.
//A variant of ObjectFactory designed specifically for injection points, allowing for programmatic optionality and lenient not-unique handling.
public interface ObjectProvider<T> extends ObjectFactory<T>, Iterable<T> {
// ...省略了部分代码
@Nullable
T getIfAvailable() throws BeansException;
}
Как видно из комментариев к исходному коду,ObjectProvider
интерфейсObjectFactory
Расширения интерфейсов, разработанные специально для точек внедрения, могут сделать внедрение более разрешительным и необязательным.
Среди них, поgetIfAvailable()
Можно видеть, что когда Bean-компонент для ввода параметров пуст или имеет несколько параметров, онObjectProvider
когда это работает.
- Если внедренный экземпляр пуст, используйте
ObjectProvider
Это позволяет избежать исключения, когда зависимый объект не существует из-за сильных зависимостей. - Если экземпляров несколько,
ObjectProvider
Метод будет реализован в соответствии с BeanOrdered
интерфейс или@Order
Получить один в порядке, указанном в аннотацииBean
, тем самым обеспечивая более расслабленный способ внедрения зависимостей
назад,RedisConnectionConfiguration
Этот конструктор родительского класса сам фактически реализует такую функцию: если пользователь предоставляетRedisSentinelConfiguration
а такжеRedisSentinelConfiguration
, будет загружен в конструктор, иRedisProperties
Это относительно просто, то есть связанная конфигурация Redis.
RedisProperties
Прочтите соответствующую конфигурацию redis из конфигурации.Простейшая конфигурация redis для одной машины — это простые атрибуты, sentinel — это связанная конфигурация дозорного, кластер — это связанная конфигурация кластера, а пул — это связанная конфигурация пула соединений. .
@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {
private int database = 0;
private String url;
private String host = "localhost";
private int port = 6379;
private String username;
private String password;
private Sentinel sentinel;
private Cluster cluster;
public static class Pool {}
public static class Cluster {}
public static class Sentinel {}
// ... 省略非必要代码
}
Подводя итог, в настоящее время мы можем видетьRedisAutoConfiguration
Зависит от класса конфигурацииLettuceConnectionConfiguration
, его конструктор считывает определяемую пользователем конфигурацию redis, которая включает в себя конфигурацию для одного компьютера + конфигурацию кластера + конфигурацию дозорного + конфигурацию пула соединений, из которых конфигурация кластера и конфигурация дозорного являются двумя bean-компонентами, которые позволяют пользователям настраивать.
createLettuceConnectionFactory
LettuceConnectionConfiguration
Вызывается в методе, реализующем пул соединений вcreateLettuceConnectionFactory
, который реализуется следующим образом
private LettuceConnectionFactory createLettuceConnectionFactory(LettuceClientConfiguration clientConfiguration) {
if (getSentinelConfig() != null) {
return new LettuceConnectionFactory(getSentinelConfig(), clientConfiguration);
}
if (getClusterConfiguration() != null) {
return new LettuceConnectionFactory(getClusterConfiguration(), clientConfiguration);
}
return new LettuceConnectionFactory(getStandaloneConfig(), clientConfiguration);
}
По сути, это прочитать конфигурацию дозорного, конфигурацию кластера и конфигурацию одиночной машины по очереди, и если она есть, создать пул подключений и вернуть его.
вgetSentinelConfig()
а такжеgetClusterConfiguration()
это метод родительского класса, который реализован следующим образом,
protected final RedisSentinelConfiguration getSentinelConfig() {
if (this.sentinelConfiguration != null) {
return this.sentinelConfiguration;
}
RedisProperties.Sentinel sentinelProperties = this.properties.getSentinel();
if (sentinelProperties != null) {
RedisSentinelConfiguration config = new RedisSentinelConfiguration();
// 省略装载代码
config.setDatabase(this.properties.getDatabase());
return config;
}
return null;
}
protected final RedisClusterConfiguration getClusterConfiguration() {
if (this.clusterConfiguration != null) {
return this.clusterConfiguration;
}
if (this.properties.getCluster() == null) {
return null;
}
RedisProperties.Cluster clusterProperties = this.properties.getCluster();
RedisClusterConfiguration config = new RedisClusterConfiguration(clusterProperties.getNodes());
// 省略装载代码
return config;
}
Отсюда мы можем узнать, что его приоритет читается в конструкторе наObjectProvider
Введены определяемые пользователем компоненты конфигурации, которые могут существовать, если нет, прочтитеRedisProperties
Завершите сборку.
Однако внимательные читатели должны спросить: а как насчет конфигурации с одной машиной?
protected final RedisStandaloneConfiguration getStandaloneConfig() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
if (StringUtils.hasText(this.properties.getUrl())) {
// 省略装载代码
}
else {
// 省略装载代码
}
config.setDatabase(this.properties.getDatabase());
return config;
}
Да, вы правильно прочитали, одинокие собаки не заслуживают...
Подводя итог, получите соответствующий bean-компонент конфигурации в конструкторе, а затем найдите его в методе создания пула соединений.Если нет, используйте файл конфигурации для его создания, но redis с одним экземпляром не поддерживается.
поднять вопрос
Защита одиночных собак является обязанностью каждого, поэтому яОт имени «Ассоциации защиты одиноких собак»Подняли вопрос в сообществе SpringBoot
Тогда начальник ответил:может защититьРад поддержать.
Среди них отмечается, что использованиеBeanPostProcessor
метод перезаписиRedisProperties
Я думал о конфигурации .