首页 文章

在spring boot中启用Redis缓存

提问于
修改于
浏览 202
5

我的 spring 启动项目有以下配置 .

@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启动应用程序上运行 . 有人能帮我解决问题吗?

我使用的是 Spring 季启动版1.4.2.RELEASE

谢谢!

1 回答

  • 8

    鉴于您使用的是Spring Boot,因此大部分Redis配置都是不必要的,因为Spring Boot为Redis提供了“自动配置”支持,无论是data source还是caching provider .

    您还没有具体说明您使用的是什么版本的Spring Boot(例如 1.5.0.RC1 )来运行您的应用程序,或者您是否在应用程序的类路径上有任何 application.properties ,如果您明确指定了 spring.cache.type (设置为除了"redis",例如) .

    但是,一般来说,我真的看不到你的Redis或Spring Cache @Configuration 类有多大问题 . 但是,如果没有明确设置 cacheManager.setUsePrefix(true) ,它似乎确实存在问题 . 当我设置这个 RedisCacheManager 属性('usePrefix`)时,一切都按预期工作 .

    我不是(Spring Data)Redis的专家,所以我不确定为什么需要它 . 但是,我的测试配置基于Spring Boot的"auto-configuration" support for Redis caching以及 @Configuration "Application"类,如上所示 .

    而且,因为您可以消除大部分显式配置并使用Spring Boot的"auto-configuration" support for Redis作为数据源,所以我在我的测试类中添加了一个 "AutoRedisConfiguration" @Configuration 类 . 即您可以使用它来配置Redis而不是我的其他 @Configuration 类( "CustomRedisConfiguration" ),它使用您的配置 fix .

    这是完整的测试示例......

    /*
     * 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;
        }
      }
    }
    

    希望这可以帮助!

    干杯,约翰

相关问题