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