[JAVA] Cache de support nul dans Spring Data Redis

L'utilisation de Spring Date Redis dans un projet Spring facilite la mise en cache sur Redis.

Cependant, l'une des difficultés de la mise en cache est de savoir s'il faut mettre en cache ** les choses nulles **. Si celui que vous avez essayé d'obtenir au fil du temps était nul (sinon), vous devez vous rappeler qu'il était nul.

Jusqu'à présent, lors de l'utilisation de Spring Date Redis, null n'était pas mis en cache. (Bien sûr, cela peut être géré en personnalisant le sérialiseur / désérialiseur) Cela a été un problème jusqu'à présent, mais il est officiellement pris en charge depuis la version 1.8.

Support caching null values via RedisCache https://jira.spring.io/browse/DATAREDIS-553

Tout ce que vous avez à faire est de définir l'argument du constructeur RedisCacheManager pour le marquer pour un support nul. Voici un exemple.

Application.java


@EnableCaching
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Autowired
    private JedisConnectionFactory jedisConnectionFactory;

    @Bean
    public RedisTemplate<Object, Object> redisTemplate() {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(jedisConnectionFactory);
        redisTemplate.setKeySerializer(new GenericJackson2JsonRedisSerializer(""));
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer(""));
        return redisTemplate;
    }

    @Bean
    public CacheManager cacheManager() {
        List<String> cacheNames = Arrays.asList("person");
        RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate(), cacheNames, true); //Enfin, cachez Null comme argument.

        //Définition du préfixe de clé de cache
        redisCacheManager.setUsePrefix(true);
        redisCacheManager.setCachePrefix(new RedisCachePrefix() {
            @Override
            public byte[] prefix(String cacheName) {
                return ("SAMPLE:" + cacheName + ":").getBytes(StandardCharsets.UTF_8);
            }
        });

        return redisCacheManager;
    }
}

Person.java


@Data
@AllArgsConstructor
public class Person {
    private int id;
    private String name;
}

PersonService.java


@Slf4j
@Service
public class PersonService {

    @Cacheable("person")
    public Person findById(int id) {
        log.info("called findById. id = {}", id);

        try {
            TimeUnit.SECONDS.sleep(id);
        } catch (InterruptedException e) {
            // ignore
        }

        return id >= 10 ? null : new Person(id, "Hogetaro" + id);
    }
}

PersonServiceTest.java


@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {

    @Autowired
    PersonService target;
    @Autowired
    CacheManager cacheManager;

    @Before
    public void setup() {
        Cache cache = cacheManager.getCache("person");
        cache.clear();
    }

    @Test
    public void testFindByIdNull() {
        StopWatch stopWatch = new StopWatch();

        stopWatch.start();
        Person p1 = target.findById(10); //Prend 10 s
        stopWatch.stop();
        log.info("result = {}, elapsed = {}", p1, stopWatch.getLastTaskTimeMillis());
        assertNull(p1);
        assertTrue(stopWatch.getLastTaskTimeMillis() > 10000);

        stopWatch.start();
        Person p2 = target.findById(10); //La deuxième fois que le cache fonctionne et est rapide
        stopWatch.stop();
        log.info("result = {}, elapsed = {}", p2, stopWatch.getLastTaskTimeMillis());
        assertNull(p2);
        assertTrue(stopWatch.getLastTaskTimeMillis() < 1000);
    }
}

TestResults


2017-06-23 12:01:34.434  INFO 3246 --- [           main] n.s.cachesample.service.PersonService    : called findById. id = 10
2017-06-23 12:01:44.449  INFO 3246 --- [           main] n.s.c.service.PersonServiceTest          : result = null, elapsed = 10058
2017-06-23 12:01:44.498  INFO 3246 --- [           main] n.s.c.service.PersonServiceTest          : result = null, elapsed = 49

À propos, la façon dont il est enregistré dans Redis est la suivante.

$ redis-cli -h 192.168.99.100 get 'SAMPLE:hello:10'                                                                                                                                                                                12:06:23
"{\"@class\":\"org.springframework.cache.support.NullValue\"}"

Cela est dû aux classes suivantes définies dans GenericJackson2JsonRedisSerializer.

NullValueSerializer


/**
 * {@link StdSerializer} adding class information required by default typing. This allows de-/serialization of
 * {@link NullValue}.
 *
 * @author Christoph Strobl
 * @since 1.8
 */
private class NullValueSerializer extends StdSerializer<NullValue> {

    private static final long serialVersionUID = 1999052150548658808L;
    private final String classIdentifier;

    /**
     * @param classIdentifier can be {@literal null} and will be defaulted to {@code @class}.
     */
    NullValueSerializer(String classIdentifier) {

        super(NullValue.class);
        this.classIdentifier = StringUtils.hasText(classIdentifier) ? classIdentifier : "@class";
    }

    /*
     * (non-Javadoc)
     * @see com.fasterxml.jackson.databind.ser.std.StdSerializer#serialize(java.lang.Object, com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider)
     */
    @Override
    public void serialize(NullValue value, JsonGenerator jgen, SerializerProvider provider)
            throws IOException {

        jgen.writeStartObject();
        jgen.writeStringField(classIdentifier, NullValue.class.getName());
        jgen.writeEndObject();
    }
}

https://github.com/spring-projects/spring-data-redis/blob/master/src/main/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializer.java

Recommended Posts

Cache de support nul dans Spring Data Redis
Existe en utilisant la spécification dans Spring Data JPA
Pour écrire des données de réponse directement dans Spring
À propos de la spécification de la période de validité lors de l'enregistrement du cache dans Redis avec Spring Cache
Créer la variable de clause where dans Spring Data JPA
Spring Boot (série 1) + spring-security-oauth2 + Redis Session + Heroku avec SerializationException
Inject Logger au printemps
Prise en charge multilingue de Spring Framework
Utilisez Interceptor au printemps
Aperçu de Spring Data JDBC
Microservices dans Spring Cloud
Obtenez des cookies au printemps
piège dynamodb de données de ressort
Créez une API pour envoyer et recevoir des données Json avec Spring