2017-01-14 33 views
4

我的彈簧引導項目具有以下配置。在彈簧啓動中啓用Redis緩存

@SpringBootApplication 
@EnableTransactionManagement 
@EnableCaching 
@EnableScheduling 
@EnableAsync 
public class Application { 

    String redisHost = "localhost"; 
    int redisPort = 6379; 

    public static void main(String[] args) { 
     SpringApplication.run(Application.class, args); 
    } 
    @Bean 
    JedisConnectionFactory jedisConnectionFactory() { 
     JedisConnectionFactory factory = new JedisConnectionFactory(); 
     factory.setHostName(redisHost); 
     factory.setPort(redisPort); 
     factory.setUsePool(true); 
     return factory; 
    } 
    @Bean 
    RedisTemplate<Object, Object> redisTemplate() { 
     RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<Object, Object>(); 
     redisTemplate.setConnectionFactory(jedisConnectionFactory()); 
     return redisTemplate; 
    } 
    @Bean 
    public CacheManager cacheManager() { 
     RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate()); 
     return cacheManager; 
    } 
} 

此外,我有以下maven依賴於pom。

<dependency> 
     <groupId>org.springframework.boot</groupId> 
     <artifactId>spring-boot-starter-data-redis</artifactId> 
    </dependency> 

我有一個單獨的Redis服務器我的本地機器上定義的端口上運行。同樣在我的服務類中,我有@Cacheable,@CachePut等註釋來支持緩存。

我可以無誤地啓動spring引導應用程序,並且CRUD操作也可以使用。但似乎它沒有使用定義的redis緩存。我使用'redi desktop manger'瀏覽工具,無法在redis上找到任何數據。另外,我嘗試通過redis cli命令「monitor」監視redis服務器,但在監視器上看不到任何更改。

所以我假設redis緩存仍然不能在我的spring啓動應用程序上工作。有人能幫我弄清楚這個問題嗎?

我正在使用彈簧啓動版本1.4.2.RELEASE

謝謝!

回答

5

由於您使用春季啓動,你得多Redis的配置是不必要的,因爲春季啓動對Redis的規定「自動配置」的支持,無論是作爲一個data source以及一個caching provider

你也沒有具體的關於你正在使用的是什麼版本春季啓動(如1.5.0.RC1)來運行你的應用程序,或者你是否對你的應用程序的類路徑中的任何application.properties,如果你明確指定spring.cache.type這可能有所作爲(例如,設置爲除「redis」以外的其他內容)。

但是,一般來說,我看不出你的Redis或Spring Cache@Configuration類有多大錯誤。然而,它沒有明確設定cacheManager.setUsePrefix(true)似乎是個問題。當我設置RedisCacheManager屬性('usePrefix`)時,一切按預期工作。

我不是(春季數據)Redis的專家,所以我不完全確定爲什麼這是必要的。但是,我的測試配置基於Spring Boot的"auto-configuration" support for Redis caching以及@Configuration「Application」類,如上所示。

而且,因爲可以消除大部分的明確的配置和使用春天啓動的"auto-configuration" support for Redis作爲數據源,以及,我加入了"AutoRedisConfiguration"@Configuration類我的測試類。即您可以使用此配置來配置Redis,而不是使用您的配置+ 修復程序的其他@Configuration類("CustomRedisConfiguration")。

下面是完整的測試例子...

/* 
* Copyright 2017 the original author or authors. 
* 
* Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. 
* You may obtain a copy of the License at 
* 
*  http://www.apache.org/licenses/LICENSE-2.0 
* 
* Unless required by applicable law or agreed to in writing, software 
* distributed under the License is distributed on an "AS IS" BASIS, 
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License. 
*/ 

package org.spring.cache; 

import static org.assertj.core.api.Assertions.assertThat; 

import java.util.Arrays; 
import java.util.Properties; 
import java.util.concurrent.atomic.AtomicBoolean; 
import javax.annotation.PostConstruct; 

import org.junit.Before; 
import org.junit.FixMethodOrder; 
import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.junit.runners.MethodSorters; 
import org.spring.cache.CachingWithRedisIntegrationTest.CachingWithRedisConfiguration; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.boot.SpringBootConfiguration; 
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 
import org.springframework.cache.CacheManager; 
import org.springframework.cache.annotation.Cacheable; 
import org.springframework.cache.annotation.EnableCaching; 
import org.springframework.cache.concurrent.ConcurrentMapCacheManager; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Import; 
import org.springframework.context.annotation.Profile; 
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; 
import org.springframework.data.redis.cache.RedisCacheManager; 
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; 
import org.springframework.data.redis.core.RedisTemplate; 
import org.springframework.test.context.ActiveProfiles; 
import org.springframework.test.context.ContextConfiguration; 
import org.springframework.test.context.junit4.SpringRunner; 
import org.springframework.util.Assert; 

/** 
* Integration tests testing Spring's Cache Abstraction using Spring Data Redis auto-configured with Spring Boot. 
* 
* To run this test, first start a Redis Server on localhost listening on the default port, 6379. 
* 
* @author John Blum 
* @see org.junit.Test 
* @since 1.0.0 
*/ 
@RunWith(SpringRunner.class) 
@ActiveProfiles("auto") 
@FixMethodOrder(MethodSorters.NAME_ASCENDING) 
@ContextConfiguration(classes = CachingWithRedisConfiguration.class) 
@SuppressWarnings("unused") 
public class CachingWithRedisIntegrationTest { 

    protected static final int REDIS_PORT = 6379; 
    protected static final String REDIS_HOST = "localhost"; 

    private AtomicBoolean setup = new AtomicBoolean(false); 

    @Autowired 
    private MathService mathService; 

    @Autowired(required = false) 
    private RedisTemplate<Object, Object> redisTemplate; 

    @Before 
    public void setup() { 
    if (redisTemplate != null && !setup.getAndSet(true)) { 
     redisTemplate.delete(Arrays.asList(0L, 1L, 2L, 4L, 8L)); 
    } 
    } 

    @Test 
    public void firstCacheMisses() { 
    assertThat(mathService.factorial(0L)).isEqualTo(1L); 
    assertThat(mathService.wasCacheMiss()).isTrue(); 
    assertThat(mathService.factorial(1L)).isEqualTo(1L); 
    assertThat(mathService.wasCacheMiss()).isTrue(); 
    assertThat(mathService.factorial(2L)).isEqualTo(2L); 
    assertThat(mathService.wasCacheMiss()).isTrue(); 
    assertThat(mathService.factorial(4L)).isEqualTo(24L); 
    assertThat(mathService.wasCacheMiss()).isTrue(); 
    assertThat(mathService.factorial(8L)).isEqualTo(40320L); 
    assertThat(mathService.wasCacheMiss()).isTrue(); 
    } 

    @Test 
    public void thenCacheHits() { 
    assertThat(mathService.factorial(0L)).isEqualTo(1L); 
    assertThat(mathService.wasCacheMiss()).isFalse(); 
    assertThat(mathService.factorial(1L)).isEqualTo(1L); 
    assertThat(mathService.wasCacheMiss()).isFalse(); 
    assertThat(mathService.factorial(2L)).isEqualTo(2L); 
    assertThat(mathService.wasCacheMiss()).isFalse(); 
    assertThat(mathService.factorial(4L)).isEqualTo(24L); 
    assertThat(mathService.wasCacheMiss()).isFalse(); 
    assertThat(mathService.factorial(8L)).isEqualTo(40320L); 
    assertThat(mathService.wasCacheMiss()).isFalse(); 
    } 

    interface MathService { 
    boolean wasCacheMiss(); 
    long factorial(long number); 
    } 

    @EnableCaching 
    @SpringBootConfiguration 
    @Import({ AutoRedisConfiguration.class, CustomRedisConfiguration.class }) 
    static class CachingWithRedisConfiguration { 

    @Bean 
    MathService mathService() { 
     return new MathService() { 
     private final AtomicBoolean cacheMiss = new AtomicBoolean(false); 

     @Override 
     public boolean wasCacheMiss() { 
      return cacheMiss.getAndSet(false); 
     } 

     @Override 
     @Cacheable(cacheNames = "Factorials") 
     public long factorial(long number) { 
      cacheMiss.set(true); 

      Assert.isTrue(number >= 0L, String.format("Number [%d] must be greater than equal to 0", number)); 

      if (number <= 2L) { 
      return (number < 2L ? 1L : 2L); 
      } 

      long result = number; 

      while (--number > 1) { 
      result *= number; 
      } 

      return result; 
     } 
     }; 
    } 

    @Bean 
    @Profile("none") 
    CacheManager cacheManager() { 
     return new ConcurrentMapCacheManager(); 
    } 
    } 

    @Profile("auto") 
    @EnableAutoConfiguration 
    @SpringBootConfiguration 
    static class AutoRedisConfiguration { 

    @PostConstruct 
    public void afterPropertiesSet() { 
     System.out.println("AUTO"); 
    } 

    @Bean 
    static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() { 
     PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = 
     new PropertySourcesPlaceholderConfigurer(); 
     propertySourcesPlaceholderConfigurer.setProperties(redisProperties()); 
     return propertySourcesPlaceholderConfigurer; 
    } 

    static Properties redisProperties() { 
     Properties redisProperties = new Properties(); 

     redisProperties.setProperty("spring.cache.type", "redis"); 
     redisProperties.setProperty("spring.redis.host", REDIS_HOST); 
     redisProperties.setProperty("spring.redis.port", String.valueOf(REDIS_PORT)); 

     return redisProperties; 
    } 
    } 

    @Profile("custom") 
    @SpringBootConfiguration 
    static class CustomRedisConfiguration { 

    @PostConstruct 
    public void afterPropertiesSet() { 
     System.out.println("CUSTOM"); 
    } 

    @Bean 
    JedisConnectionFactory jedisConnectionFactory() { 
     JedisConnectionFactory factory = new JedisConnectionFactory(); 
     factory.setHostName(REDIS_HOST); 
     factory.setPort(REDIS_PORT); 
     factory.setUsePool(true); 
     return factory; 
    } 

    @Bean 
    RedisTemplate<Object, Object> redisTemplate() { 
     RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>(); 
     redisTemplate.setConnectionFactory(jedisConnectionFactory()); 
     return redisTemplate; 
    } 

    @Bean 
    CacheManager cacheManager() { 
     RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate()); 
     cacheManager.setUsePrefix(true); // THIS IS NEEDED! 
     return cacheManager; 
    } 
    } 
} 

希望這有助於!

乾杯, 約翰

+0

注:我測試類我與_Spring Boot_'1.5.0.RC1'還有'彈簧引導起動數據redis'運行。在我的'AutoRedisConfiguration'類中,我明確地將'spring.cache.type'設置爲Redis,因爲我的測試項目中還有其他一些使用其他緩存提供程序的示例,如Pivotal GemFire,Apache Geode和Hazelcast,但這並非嚴格必要如果您在類路徑中的Spring Boot的自動配置支持中沒有其他可能的緩存提供者。 –

+0

謝謝,我會讓你知道結果。我的春季啓動版本是1.4.2.RELEASE – lsc