web-dev-qa-db-fra.com

Activation du cache Redis dans Spring Boot

J'ai la configuration suivante sur mon projet Spring Boot.

@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;
    }
}

J'ai aussi la dépendance maven suivante sur pom.

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

J'ai un serveur redis distinct fonctionnant sur ma machine locale sur un port défini. Également dans mes classes de service, j'ai des annotations comme @Cacheable, @CachePut pour prendre en charge la mise en cache.

Je peux démarrer l'application Spring Boot sans erreurs et les opérations CRUD fonctionnent également. Mais il semble qu'il n'utilise pas le cache redis défini. J'ai utilisé l'outil de navigation "redi desktop manger" et je n'ai trouvé aucune donnée sur redis. J'ai également essayé de surveiller le serveur redis via la commande redis cli 'monitor', je ne vois aucun changement sur le moniteur.

Je suppose donc que la mise en cache redis ne fonctionne toujours pas sur mon application Spring Boot. Quelqu'un peut-il m'aider à comprendre le problème?

J'utilise la version Spring Boot 1.4.2.

Merci!

8
lsc

Étant donné que vous utilisez Spring Boot, une grande partie de votre configuration Redis est inutile car Spring Boot ​​fournit la prise en charge "auto-configuration" pour Redis, à la fois comme a source de données ainsi que fournisseur de cache .

Vous n'étiez pas non plus précis sur la version de Spring Boot ​​que vous utilisiez (par exemple 1.5.0.RC1) Pour exécuter votre application, ou si vous aviez application.properties Sur le chemin d'accès aux classes de votre application , ce qui pourrait faire une différence si vous spécifiez explicitement spring.cache.type (défini sur autre chose que "redis", par exemple).

Cependant, en général, je ne vois vraiment pas grand-chose de mal avec votre classe Redis ou Spring Cache@Configuration. Cependant, cela ne semble pas poser de problème en ne définissant pas explicitement cacheManager.setUsePrefix(true). Lorsque j'ai défini cette propriété RedisCacheManager ('usePrefix`), tout a fonctionné comme prévu.

Je ne suis pas (Spring Data) expert Redis donc je ne sais pas exactement pourquoi cela est nécessaire. Cependant, j'ai basé ma configuration de test sur Spring Boot's"auto-configuration" support pour la mise en cache Redis ainsi que votre @Configuration Classe "Application", illustrée ci-dessus.

Et, parce que vous pouvez éliminer la plupart de votre configuration explicite et utiliser Spring Boot's"auto-configuration" support pour Redis comme source de données également , J'ai ajouté une classe "AutoRedisConfiguration"@Configuration À ma classe de test. C'est à dire. vous pouvez l'utiliser pour configurer Redis au lieu de mon autre classe @Configuration ("CustomRedisConfiguration") qui utilise votre configuration + le correctif .

Voici l'exemple de test complet ...

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

J'espère que cela t'aides!

À la vôtre, John

11
John Blum

J'utilise Spring Boot 2.0 et son Redis très simple à utiliser à des fins de mise en cache simple.

  1. Annotez votre application de démarrage Spring avec @EnableCaching
  2. Dans votre application, les propriétés ont ces propriétés

    spring.cache.type = redis redis.Host.url = redis.Host.port =

  3. Annotez vos méthodes avec @Cacheable.

C'est tout!!

Si vous utilisez AWS Elasticache et que vous avez vérifié le chiffrement en transit, vous devez ajouter un fichier RedisConfiguration pour définir votre SSL sur true.

Spring Boot 2.0 utilise désormais LettuceConnectionFactory.

Pour faire ce qui précède, ajoutez simplement une classe et marquez-la avec l'annotation @Configuration et ajoutez le bean suivant

@Bean
  public LettuceConnectionFactory redisConnectionFactory() {
    RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
    configuration.setHostName(redisHost);
    configuration.setPort(redisPort);
    return new LettuceConnectionFactory(configuration,            LettuceClientConfiguration.builder().useSsl().disablePeerVerification().build());
  }
1
Sukalpo

Vous pouvez vérifier l'existence de vos clés dans redis avec la commande dans redis-cli: keys *

S'il y aura votre clé, tout va bien :)

0
S.Dayneko