2017-01-14 43 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