1. 程式人生 > >Spring Boot 使用Redis拒絕連線以及獲取不到連線池

Spring Boot 使用Redis拒絕連線以及獲取不到連線池

使用環境

  1. 使用spring boot構建上層服務專案
  2. redis快取相關方法寫到公共工具類,被上層服務依賴 common-utils
  3. redis是安裝在本地虛擬機器中

啟動服務,首先程式報錯為拒絕連線:

然後使用本地視覺化工具進行測試連線,顯示同樣的錯誤
connection refused

解決方法:

  1. 首先在redis.conf中註釋掉bind 127.0.0.1這一行,其意思是隻允許本地訪問連線,其他Ip都將被拒絕.
  2. 如果第一步操作過後,依然拒絕連線,可能為redis部署機器的防火牆沒有關閉或者網路不通,進行如下操作:

2.1. 首先檢查自己的網路,是否可以ping通
2.2. 檢查埠 netstat -tunlp |grep 6379


tcp 0 0 0.0.0.0:6379 0.0.0.0:* LISTEN 3227/redis-server *,檢視結果也是ok的.
2.3 伺服器防火牆的問題,關了防火牆試下:
systemctl stop firewalld.service(我的遠端機器是centos7)

補充:
systemctl stop firewalld.service #停止firewall
systemctl disable firewalld.service #禁止firewall開機啟動
執行下面這段命令就可以開放6379埠了
firewall-cmd --zone=public --add-port=6379/tcp --permanent

至此本地視覺化工具已經連線可用;

啟動spring boot程式,無法獲取到RedisTemplate

2438927-0ddc1ae83dd1e926.png

jar包使用@Configuration配置redis快取
程式碼如下:

@Configuration
@EnableCaching
@PropertySource("classpath:RedisConfig.properties")
public class RedisConfig extends CachingConfigurerSupport{
    @Bean
    public KeyGenerator wiselyKeyGenerator(){
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                StringBuilder sb = new StringBuilder();
                sb.append(target.getClass().getName());
                sb.append(method.getName());
                for (Object obj : params) {
                    sb.append(obj.toString());
                }
                return sb.toString();
            }
        };
    }
    @Bean
    public CacheManager cacheManager(
            @SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {
        return new RedisCacheManager(redisTemplate);
    }
    @Bean
    public RedisTemplate<String, String> redisTemplate(
            RedisConnectionFactory factory) {
        StringRedisTemplate template = new StringRedisTemplate(factory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}

屬性檔案在common-util包中,RedisConfig.properties內容如下:

# REDIS (RedisProperties)
# Redis資料庫索引(預設為0)
spring.redis.database=0
# Redis伺服器地址
spring.redis.host=192.168.22.111
# Redis伺服器連線埠
spring.redis.port=6379
# Redis伺服器連線密碼(預設為空)
spring.redis.password=
# 連線池最大連線數(使用負值表示沒有限制)
spring.redis.pool.max-active=8
# 連線池最大阻塞等待時間(使用負值表示沒有限制)
spring.redis.pool.max-wait=-1
# 連線池中的最大空閒連線
spring.redis.pool.max-idle=8
# 連線池中的最小空閒連線
spring.redis.pool.min-idle=0
# 連線超時時間(毫秒)

開始懷疑spring boot不會自動掃描jar包中的@Configuration註解,測試過後,這個是完全可以的;
接下來開始除錯,發現redis使用的是預設連線(127.0.0.1:6379)並沒有讀取到我的屬性檔案,原來spring boot不能預設讀取jar包中的屬性檔案,需要我們手工指定裝載進來:
@Configuration註解那裡加上@PropertySource("classpath:RedisConfig.properties")

接下來問題又出現了:

Description:
Field template in org.pekxxoo.redis.RedisUtil required a single bean, but 2 were found:
    - redisTemplate: defined by method 'redisTemplate' in class path resource [org/pekxxoo/redis/RedisConfig.class]
    - stringRedisTemplate: defined by method 'stringRedisTemplate' in class path resource [org/springframework/boot/autoconfigure/data/redis/RedisAutoConfiguration$RedisConfiguration.class]

看說明,可以知道,是因為@Autowired在注入時,是匹配型別的,如果存在兩個一個型別的例項時就會報錯,報錯資訊指出,一個redisTemplate是在我的RedisConfig.class中配置的,另一個是RedisAutoConfiguration中進行宣告的,因此兩種解決方案:

  1. 在啟動類處加上註解:@EnableAutoConfiguration(exclude = RedisAutoConfiguration.class)關閉自動注入配置;
  2. 在RedisUtil.class注入時結合@Qualifier("")註解:
@Qualifier("redisTemplate")
@Autowired
private RedisTemplate<String,String> template;

至此spring boot 結合redis快取終於啟動成功;