redis 在 spring容器的核心类

  1. StringRedisTemplate 和 RedisTemplate
  2. 客户端工厂 LettuceConnectionFactory 也可以使用 JedisConnectionFactory

配置文件

  1. redis:
  2. base:
  3. host: 192.168.8.165
  4. port: 6379
  5. database: 0
  6. timeout: 3000
  7. lettuce:
  8. pool:
  9. min-idle: 5
  10. max-idle: 10
  11. max-active: 8
  12. max-wait: 1ms
  13. report:
  14. host: cache164.e6xayf.com
  15. port: 6379
  16. database: 12
  17. timeout: 3000
  18. lettuce:
  19. pool:
  20. min-idle: 5
  21. max-idle: 10
  22. max-active: 8
  23. max-wait: 1ms

配置类

参照 RedisAutoConfiguration 和 LettuceConnectionConfiguration

  1. package com.alibaba.project.config;
  2. import io.lettuce.core.resource.ClientResources;
  3. import io.lettuce.core.resource.DefaultClientResources;
  4. import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
  5. import org.springframework.beans.factory.annotation.Qualifier;
  6. import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
  7. import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
  8. import org.springframework.boot.context.properties.ConfigurationProperties;
  9. import org.springframework.context.annotation.Bean;
  10. import org.springframework.context.annotation.Configuration;
  11. import org.springframework.context.annotation.Primary;
  12. import org.springframework.data.redis.connection.RedisConnectionFactory;
  13. import org.springframework.data.redis.connection.RedisPassword;
  14. import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
  15. import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
  16. import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
  17. import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
  18. import org.springframework.data.redis.core.StringRedisTemplate;
  19. /**
  20. * @author demon
  21. * @date 2021/3/1 11:08
  22. */
  23. @Configuration
  24. @ConfigurationProperties(prefix = "redis")
  25. public class RedisConfig {
  26. private RedisProperties base;
  27. private RedisProperties report;
  28. @Bean(destroyMethod = "shutdown")
  29. @ConditionalOnMissingBean(ClientResources.class)
  30. public DefaultClientResources lettuceClientResources() {
  31. return DefaultClientResources.create();
  32. }
  33. @Bean(name = "baseStringRedisTemplate")
  34. @Primary
  35. public StringRedisTemplate baseStringRedisTemplate(
  36. @Qualifier("baseLettuceConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
  37. StringRedisTemplate template = new StringRedisTemplate();
  38. template.setConnectionFactory(redisConnectionFactory);
  39. return template;
  40. }
  41. @Bean(name = "baseLettuceConnectionFactory")
  42. @Primary
  43. public LettuceConnectionFactory baseLettuceConnectionFactory(ClientResources clientResources) {
  44. RedisStandaloneConfiguration redis1StandaloneConfiguration = getStandaloneConfig(base);
  45. LettuceClientConfiguration clientConfig = getLettuceClientConfiguration(clientResources, base);
  46. return new LettuceConnectionFactory(redis1StandaloneConfiguration, clientConfig);
  47. }
  48. @Bean(name = "reportStringRedisTemplate")
  49. public StringRedisTemplate reportStringRedisTemplate(
  50. @Qualifier("reportLettuceConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
  51. StringRedisTemplate template = new StringRedisTemplate();
  52. template.setConnectionFactory(redisConnectionFactory);
  53. return template;
  54. }
  55. @Bean(name = "reportLettuceConnectionFactory")
  56. public LettuceConnectionFactory reportLettuceConnectionFactory(ClientResources clientResources) {
  57. RedisStandaloneConfiguration redis1StandaloneConfiguration = getStandaloneConfig(report);
  58. LettuceClientConfiguration clientConfig = getLettuceClientConfiguration(clientResources, report);
  59. return new LettuceConnectionFactory(redis1StandaloneConfiguration, clientConfig);
  60. }
  61. /**
  62. * redis standalone config
  63. *
  64. * @param redisProperties redis 配置参数
  65. * @return RedisStandaloneConfiguration
  66. */
  67. private RedisStandaloneConfiguration getStandaloneConfig(RedisProperties redisProperties) {
  68. RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
  69. config.setHostName(redisProperties.getHost());
  70. config.setPort(redisProperties.getPort());
  71. config.setPassword(RedisPassword.of(redisProperties.getPassword()));
  72. config.setDatabase(redisProperties.getDatabase());
  73. return config;
  74. }
  75. /**
  76. * 构建 LettuceClientConfiguration
  77. *
  78. * @param clientResources clientResources
  79. * @param redisProperties redisProperties
  80. * @return LettuceClientConfiguration
  81. */
  82. private LettuceClientConfiguration getLettuceClientConfiguration(ClientResources clientResources,
  83. RedisProperties redisProperties) {
  84. LettuceClientConfiguration.LettuceClientConfigurationBuilder builder =
  85. createBuilder(redisProperties.getLettuce().getPool());
  86. if (redisProperties.isSsl()) {
  87. builder.useSsl();
  88. }
  89. if (redisProperties.getTimeout() != null) {
  90. builder.commandTimeout(redisProperties.getTimeout());
  91. }
  92. if (redisProperties.getLettuce() != null) {
  93. RedisProperties.Lettuce lettuce = redisProperties.getLettuce();
  94. if (lettuce.getShutdownTimeout() != null
  95. && !lettuce.getShutdownTimeout().isZero()) {
  96. builder.shutdownTimeout(
  97. redisProperties.getLettuce().getShutdownTimeout());
  98. }
  99. }
  100. builder.clientResources(clientResources);
  101. return builder.build();
  102. }
  103. /**
  104. * 创建 LettuceClientConfigurationBuilder
  105. *
  106. * @param pool 连接池配置
  107. * @return LettuceClientConfigurationBuilder
  108. */
  109. private LettuceClientConfiguration.LettuceClientConfigurationBuilder createBuilder(RedisProperties.Pool pool) {
  110. if (pool == null) {
  111. return LettuceClientConfiguration.builder();
  112. }
  113. return LettucePoolingClientConfiguration.builder()
  114. .poolConfig(getPoolConfig(pool));
  115. }
  116. /**
  117. * pool config
  118. *
  119. * @param properties redis 参数配置
  120. * @return GenericObjectPoolConfig
  121. */
  122. private GenericObjectPoolConfig getPoolConfig(RedisProperties.Pool properties) {
  123. GenericObjectPoolConfig config = new GenericObjectPoolConfig();
  124. config.setMaxTotal(properties.getMaxActive());
  125. config.setMaxIdle(properties.getMaxIdle());
  126. config.setMinIdle(properties.getMinIdle());
  127. if (properties.getMaxWait() != null) {
  128. config.setMaxWaitMillis(properties.getMaxWait().toMillis());
  129. }
  130. return config;
  131. }
  132. public RedisProperties getBase() {
  133. return base;
  134. }
  135. public void setBase(RedisProperties base) {
  136. this.base = base;
  137. }
  138. public RedisProperties getReport() {
  139. return report;
  140. }
  141. public void setReport(RedisProperties report) {
  142. this.report = report;
  143. }
  144. }

使用

使用 Qualifier 注解指定 StringRedisTemplate 完成注入

优化

上面如果在加一个redis 配置,还需要修改redis 配置类,这是不优雅的。我们可以通过配置文件指定一个 primary 的redis 数据源,其他通过名称+StringRedisTemplate 的方式注入。只增加配置文件,不修改代码,完成注入。这才是比较优雅的解决方案。

注入时,我们通过 beanFactory 以编程的方式注入,这就不会存在硬编码。

  1. public synchronized void setCosBean(String beanName, Class<?> clazz, ConstructorArgumentValues original) {
  2. DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
  3. if (beanFactory.containsBean(beanName)) {
  4. return;
  5. }
  6. GenericBeanDefinition definition = new GenericBeanDefinition();
  7. definition.setBeanClass(clazz);
  8. if(beanName.startsWith(primaryKey)){
  9. definition.setPrimary(true);
  10. }
  11. //属性赋值
  12. definition.setConstructorArgumentValues(new ConstructorArgumentValues(original));
  13. //注册到spring上下文
  14. beanFactory.registerBeanDefinition(beanName, definition);
  15. }