Die Verwendung von "Spring Date Redis" in einem Spring-Projekt erleichtert das Zwischenspeichern in Redis.
Eine der Schwierigkeiten beim Zwischenspeichern ist jedoch, ob ** Null-Dinge ** zwischengespeichert werden sollen. Wenn derjenige, den Sie im Laufe der Zeit versucht haben, null war (wenn nicht), möchten Sie sich daran erinnern, dass er null war.
Bisher wurde bei Verwendung von "Spring Date Redis" null nicht zwischengespeichert. (Natürlich kann dies durch Anpassen des Serializers / Deserializers behoben werden.) Dies war bisher ein Problem, wurde jedoch seit Version 1.8 offiziell unterstützt.
Support caching null values via RedisCache https://jira.spring.io/browse/DATAREDIS-553
Alles, was Sie tun müssen, ist das Konstruktorargument "RedisCacheManager" so zu setzen, dass es für die Nullunterstützung markiert wird. Unten ist ein Beispiel.
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); //Schließlich Cache Null als Argument.
//Festlegen des Cache-Schlüsselpräfix
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); //Dauert 10s
stopWatch.stop();
log.info("result = {}, elapsed = {}", p1, stopWatch.getLastTaskTimeMillis());
assertNull(p1);
assertTrue(stopWatch.getLastTaskTimeMillis() > 10000);
stopWatch.start();
Person p2 = target.findById(10); //Das zweite Mal funktioniert der Cache und ist schnell
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
Übrigens, wie es in Redis gespeichert wird, ist wie folgt.
$ redis-cli -h 192.168.99.100 get 'SAMPLE:hello:10' 12:06:23
"{\"@class\":\"org.springframework.cache.support.NullValue\"}"
Dies liegt an den folgenden Klassen, die in GenericJackson2JsonRedisSerializer definiert sind.
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