飞道的博客

Spring源码阅读<二> spring-boot-redis

539人阅读  评论(0)

先看spring-boot-redis的grade构建文件


  
  1. plugins {
  2. id "org.springframework.boot.starter"
  3. }
  4. description = "Starter for using Redis key-value data store with Spring Data Redis and the Lettuce client"
  5. dependencies {
  6. api(project( ":spring-boot-project:spring-boot-starters:spring-boot-starter"))
  7. api( "org.springframework.data:spring-data-redis")
  8. api( "io.lettuce:lettuce-core")
  9. }

他依赖了spring-data-redis,等下就看看这部分内容

先来看看spring-boot-redis的autoConfig内容。

spring-boot-autoconfig并没有为redis单独建个目录,redis的内容放在cache目录下。

其实,autoconfig所有扫描文件都会被扫描到并根据各种@Conditional条件,来判断该配置是否生效并纳入容器中。

cache目录的配置类入口,我认为是CacheAutoConfiguration


  
  1. @AutoConfiguration(after = { CouchbaseDataAutoConfiguration.class, HazelcastAutoConfiguration.class,
  2. HibernateJpaAutoConfiguration.class, RedisAutoConfiguration.class })
  3. @ConditionalOnClass(CacheManager.class)
  4. @ConditionalOnBean(CacheAspectSupport.class)
  5. @ConditionalOnMissingBean(value = CacheManager.class, name = "cacheResolver")
  6. @EnableConfigurationProperties(CacheProperties.class)
  7. @Import({ CacheConfigurationImportSelector.class, CacheManagerEntityManagerFactoryDependsOnPostProcessor.class })
  8. public class CacheAutoConfiguration {
  9. }

我们先看redis的配置,在CacheAutoConfiguration里面声明RedisAutoConfiguration已经先实例化好了。


  
  1. @AutoConfiguration
  2. @ConditionalOnClass(RedisOperations.class)
  3. @EnableConfigurationProperties(RedisProperties.class)
  4. @Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
  5. public class RedisAutoConfiguration {
  6. @Bean
  7. @ConditionalOnMissingBean(name = "redisTemplate")
  8. @ConditionalOnSingleCandidate(RedisConnectionFactory.class)
  9. public RedisTemplate<Object, Object> redisTemplate (RedisConnectionFactory redisConnectionFactory) {
  10. RedisTemplate<Object, Object> template = new RedisTemplate<>();
  11. template.setConnectionFactory(redisConnectionFactory);
  12. return template;
  13. }
  14. @Bean
  15. @ConditionalOnMissingBean
  16. @ConditionalOnSingleCandidate(RedisConnectionFactory.class)
  17. public StringRedisTemplate stringRedisTemplate (RedisConnectionFactory redisConnectionFactory) {
  18. return new StringRedisTemplate(redisConnectionFactory);
  19. }
  20. }

通过RedisProperties引入了redis的配置,通过@Import  JedisConnectionConfiguration的形式引进了RedisConnetionFactory,并将RedisConnectionFactor传给了Template

再看看JedisConnectionConfiguration,因为它继承了RedisConnectionConfiguration,所以我们先看看RedisConnectionConfiguration有什么逻辑


  
  1. package org.springframework.boot.autoconfigure.data.redis;
  2. import java.net.URI;
  3. import java.net.URISyntaxException;
  4. import java.util.ArrayList;
  5. import java.util.List;
  6. import org.springframework.beans.factory.ObjectProvider;
  7. import org.springframework.boot.autoconfigure.data.redis.RedisProperties.Pool;
  8. import org.springframework.data.redis.connection.RedisClusterConfiguration;
  9. import org.springframework.data.redis.connection.RedisNode;
  10. import org.springframework.data.redis.connection.RedisPassword;
  11. import org.springframework.data.redis.connection.RedisSentinelConfiguration;
  12. import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
  13. import org.springframework.util.ClassUtils;
  14. import org.springframework.util.StringUtils;
  15. /**
  16. * Base Redis connection configuration.
  17. *
  18. * @author Mark Paluch
  19. * @author Stephane Nicoll
  20. * @author Alen Turkovic
  21. * @author Scott Frederick
  22. * @author Eddú Meléndez
  23. */
  24. abstract class RedisConnectionConfiguration {
  25. private static final boolean COMMONS_POOL2_AVAILABLE = ClassUtils.isPresent( "org.apache.commons.pool2.ObjectPool",
  26. RedisConnectionConfiguration.class.getClassLoader());
  27. private final RedisProperties properties;
  28. private final RedisStandaloneConfiguration standaloneConfiguration;
  29. private final RedisSentinelConfiguration sentinelConfiguration;
  30. private final RedisClusterConfiguration clusterConfiguration;
  31. protected RedisConnectionConfiguration (RedisProperties properties,
  32. ObjectProvider<RedisStandaloneConfiguration> standaloneConfigurationProvider,
  33. ObjectProvider<RedisSentinelConfiguration> sentinelConfigurationProvider,
  34. ObjectProvider<RedisClusterConfiguration> clusterConfigurationProvider) {
  35. this.properties = properties;
  36. this.standaloneConfiguration = standaloneConfigurationProvider.getIfAvailable();
  37. this.sentinelConfiguration = sentinelConfigurationProvider.getIfAvailable();
  38. this.clusterConfiguration = clusterConfigurationProvider.getIfAvailable();
  39. }
  40. protected final RedisStandaloneConfiguration getStandaloneConfig () {
  41. if ( this.standaloneConfiguration != null) {
  42. return this.standaloneConfiguration;
  43. }
  44. RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
  45. if (StringUtils.hasText( this.properties.getUrl())) {
  46. ConnectionInfo connectionInfo = parseUrl( this.properties.getUrl());
  47. config.setHostName(connectionInfo.getHostName());
  48. config.setPort(connectionInfo.getPort());
  49. config.setUsername(connectionInfo.getUsername());
  50. config.setPassword(RedisPassword.of(connectionInfo.getPassword()));
  51. }
  52. else {
  53. config.setHostName( this.properties.getHost());
  54. config.setPort( this.properties.getPort());
  55. config.setUsername( this.properties.getUsername());
  56. config.setPassword(RedisPassword.of( this.properties.getPassword()));
  57. }
  58. config.setDatabase( this.properties.getDatabase());
  59. return config;
  60. }
  61. protected final RedisSentinelConfiguration getSentinelConfig () {
  62. if ( this.sentinelConfiguration != null) {
  63. return this.sentinelConfiguration;
  64. }
  65. RedisProperties. Sentinel sentinelProperties = this.properties.getSentinel();
  66. if (sentinelProperties != null) {
  67. RedisSentinelConfiguration config = new RedisSentinelConfiguration();
  68. config.master(sentinelProperties.getMaster());
  69. config.setSentinels(createSentinels(sentinelProperties));
  70. config.setUsername( this.properties.getUsername());
  71. if ( this.properties.getPassword() != null) {
  72. config.setPassword(RedisPassword.of( this.properties.getPassword()));
  73. }
  74. config.setSentinelUsername(sentinelProperties.getUsername());
  75. if (sentinelProperties.getPassword() != null) {
  76. config.setSentinelPassword(RedisPassword.of(sentinelProperties.getPassword()));
  77. }
  78. config.setDatabase( this.properties.getDatabase());
  79. return config;
  80. }
  81. return null;
  82. }
  83. /**
  84. * Create a {@link RedisClusterConfiguration} if necessary.
  85. * @return {@literal null} if no cluster settings are set.
  86. */
  87. protected final RedisClusterConfiguration getClusterConfiguration () {
  88. if ( this.clusterConfiguration != null) {
  89. return this.clusterConfiguration;
  90. }
  91. if ( this.properties.getCluster() == null) {
  92. return null;
  93. }
  94. RedisProperties. Cluster clusterProperties = this.properties.getCluster();
  95. RedisClusterConfiguration config = new RedisClusterConfiguration(clusterProperties.getNodes());
  96. if (clusterProperties.getMaxRedirects() != null) {
  97. config.setMaxRedirects(clusterProperties.getMaxRedirects());
  98. }
  99. config.setUsername( this.properties.getUsername());
  100. if ( this.properties.getPassword() != null) {
  101. config.setPassword(RedisPassword.of( this.properties.getPassword()));
  102. }
  103. return config;
  104. }
  105. protected final RedisProperties getProperties () {
  106. return this.properties;
  107. }
  108. protected boolean isPoolEnabled (Pool pool) {
  109. Boolean enabled = pool.getEnabled();
  110. return (enabled != null) ? enabled : COMMONS_POOL2_AVAILABLE;
  111. }
  112. private List<RedisNode> createSentinels (RedisProperties.Sentinel sentinel) {
  113. List<RedisNode> nodes = new ArrayList<>();
  114. for (String node : sentinel.getNodes()) {
  115. try {
  116. nodes.add(RedisNode.fromString(node));
  117. }
  118. catch (RuntimeException ex) {
  119. throw new IllegalStateException( "Invalid redis sentinel property '" + node + "'", ex);
  120. }
  121. }
  122. return nodes;
  123. }
  124. protected ConnectionInfo parseUrl (String url) {
  125. try {
  126. URI uri = new URI(url);
  127. String scheme = uri.getScheme();
  128. if (! "redis".equals(scheme) && ! "rediss".equals(scheme)) {
  129. throw new RedisUrlSyntaxException(url);
  130. }
  131. boolean useSsl = ( "rediss".equals(scheme));
  132. String username = null;
  133. String password = null;
  134. if (uri.getUserInfo() != null) {
  135. String candidate = uri.getUserInfo();
  136. int index = candidate.indexOf( ':');
  137. if (index >= 0) {
  138. username = candidate.substring( 0, index);
  139. password = candidate.substring(index + 1);
  140. }
  141. else {
  142. password = candidate;
  143. }
  144. }
  145. return new ConnectionInfo(uri, useSsl, username, password);
  146. }
  147. catch (URISyntaxException ex) {
  148. throw new RedisUrlSyntaxException(url, ex);
  149. }
  150. }
  151. static class ConnectionInfo {
  152. private final URI uri;
  153. private final boolean useSsl;
  154. private final String username;
  155. private final String password;
  156. ConnectionInfo(URI uri, boolean useSsl, String username, String password) {
  157. this.uri = uri;
  158. this.useSsl = useSsl;
  159. this.username = username;
  160. this.password = password;
  161. }
  162. boolean isUseSsl () {
  163. return this.useSsl;
  164. }
  165. String getHostName () {
  166. return this.uri.getHost();
  167. }
  168. int getPort () {
  169. return this.uri.getPort();
  170. }
  171. String getUsername () {
  172. return this.username;
  173. }
  174. String getPassword () {
  175. return this.password;
  176. }
  177. }
  178. }

它的逻辑,首先它定义了一个parse方法,对URL进行解析,获取到uri,username和password,并生成了一个Connection对象

然后定义了getStandaloneConfig方法,这个方法主要是完成RedisStandaloneConfig的初始化并返回 ,先判断properties中的url配置是否为空,不为空则调用parse()方法完成RedisStandaloneConfiguration的初始化,为空则用Properties的username等属性完成初始化

再来看JedisConnectionConfiguration类

它主要用createJedisConnectionFactory方法完成JedisConnectionFactory的创建


  
  1. private JedisConnectionFactory createJedisConnectionFactory (
  2. ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) {
  3. JedisClientConfiguration clientConfiguration = getJedisClientConfiguration(builderCustomizers);
  4. if (getSentinelConfig() != null) {
  5. return new JedisConnectionFactory(getSentinelConfig(), clientConfiguration);
  6. }
  7. if (getClusterConfiguration() != null) {
  8. return new JedisConnectionFactory(getClusterConfiguration(), clientConfiguration);
  9. }
  10. return new JedisConnectionFactory(getStandaloneConfig(), clientConfiguration);
  11. }

可以看到它调用了getStandaloneConfig()方法,做为其中一个参数,还调用getJedisClientConfiguration()方法


  
  1. private JedisClientConfiguration getJedisClientConfiguration (
  2. ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) {
  3. JedisClientConfigurationBuilder builder = applyProperties(JedisClientConfiguration.builder());
  4. RedisProperties. Pool pool = getProperties().getJedis().getPool();
  5. if (isPoolEnabled(pool)) {
  6. applyPooling(pool, builder);
  7. }
  8. if (StringUtils.hasText(getProperties().getUrl())) {
  9. customizeConfigurationFromUrl(builder);
  10. }
  11. builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
  12. return builder.build();
  13. }

在applyPooling方法里面,用了RedisProperties.Pool pool的属性完成JedisPoolConfig的初始化


  
  1. private void applyPooling (RedisProperties.Pool pool,
  2. JedisClientConfiguration.JedisClientConfigurationBuilder builder) {
  3. builder.usePooling().poolConfig(jedisPoolConfig(pool));
  4. }
  5. private JedisPoolConfig jedisPoolConfig (RedisProperties.Pool pool) {
  6. JedisPoolConfig config = new JedisPoolConfig();
  7. config.setMaxTotal(pool.getMaxActive());
  8. config.setMaxIdle(pool.getMaxIdle());
  9. config.setMinIdle(pool.getMinIdle());
  10. if (pool.getTimeBetweenEvictionRuns() != null) {
  11. config.setTimeBetweenEvictionRuns(pool.getTimeBetweenEvictionRuns());
  12. }
  13. if (pool.getMaxWait() != null) {
  14. config.setMaxWait(pool.getMaxWait());
  15. }
  16. return config;
  17. }


转载:https://blog.csdn.net/AAA821/article/details/128309213
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场