Spring RedisTemplate: Сериализовать несколько классов модели в JSON. Нужно использовать несколько RedisTemplates?

Я использую Spring поддержку Redis для сохранения моих объектов в Redis.

У меня есть несколько DAO, которые обрабатывают разные классы Model:

например: "ShopperHistoryDao", который будет сохранять/извлекать объекты "ShopperHistoryModel", "ShopperItemHistoryDao", который будет обрабатывать объекты "ItemHistoryModel"

Я хочу использовать "JacksonJsonRedisSerializer" для сериализации/десериализации моих объектов в/из json.

Но в конструкторе JacksonJsonRedisSerializer он принимает один конкретный класс модели.

JacksonJsonRedisSerializer(Class<T> type)

Означает ли это, что мне нужно настроить отдельные RedisTemplates для каждого класса модели и использовать их в соответствующей реализации DAO?

Что-то вроде:

<bean id="redisTemplateForShopperHistoryModel" class="org.springframework.data.redis.core.RedisTemplate">
    <property name="connectionFactory" ref="jedisConnectionFactory" />
    <property name="valueSerializer">
        <bean id="redisJsonSerializer" 
                        class="org.springframework.data.redis.serializer.JacksonJsonRedisSerializer">
            <constructor-arg type="java.lang.Class" value="ShopperHistoryModel.class"/>
        </bean>   
    </property>
</bean>


<bean id="redisTemplateForItemHistoryModel" class="org.springframework.data.redis.core.RedisTemplate">
    <property name="connectionFactory" ref="jedisConnectionFactory" />
    <property name="valueSerializer">
        <bean id="redisJsonSerializer" 
                        class="org.springframework.data.redis.serializer.JacksonJsonRedisSerializer">
            <constructor-arg type="java.lang.Class" value="ItemHistoryModel.class"/>
        </bean>   
    </property>
</bean>

Ответы

Ответ 1

GenericJackson2JsonRedisSerializer должен сделать эту работу

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

Это добавит свойство @Class в JSON, чтобы понять тип, что поможет Джексону десериализоваться, поэтому нет необходимости явно отображать модель в классе конфигурации.

"{\"@class\":\"com.prnv.model.WhitePaper\",\"title\":\"Hey\",\"author\":{\"@class\":\"com.prnv.model.Author\",\"name\":\"Hello\"},\"description\":\"Description\"}"

В сервисе вы можете кешировать модель используя

    @Cacheable(value = "whitePaper", key = "#title")
    public WhitePaper findWhitePaperByTitle(String title) 
    {
        WhitePaper whitePaper = repository.findByTitle(title);
        return whitePaper;
    }

Проверьте эту статью: http://blog.pranavek.com/2016/12/25/integrating-redis-with-spring-application

Ответ 2

Да, RedisTemplate, похоже, предназначен для того, чтобы иметь один экземпляр сериализатора значений.

Я собирался предложить возможное обходное решение с RedisSerializer, которое содержит карту внутренних сериализаторов, поэтому вы можете использовать один RedisTemplate с сериализатором, который может обрабатывать несколько типов, но так как RedisSerializer не предлагает методы например boolean canDeserialize(..) (поскольку HTTP MessageConverters в Spring MVC есть) это не представляется возможным.

Итак, кажется, что вы застряли в наличии нескольких экземпляров RedisTemplate.

Ответ 3

Немного старого потока, но вы можете сделать что-то вроде этого:

<bean id="RedisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
    <property name="connectionFactory" ref="jedisConnectionFactory" />
    <property name="valueSerializer">
        <bean id="jackson2JsonRedisSerializer" 
                        class="org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer">
            <constructor-arg type="java.lang.Class" value="Object.class" />
        </bean>   
    </property>
</bean>

Затем в вашем классе Java

@Autowire
private RedisTemplate redisTemplate;

public void save(Model model) {
    ObjectMapper obmap = new ObjectMapper();
    redisTemplate.opsForHash().putAll(mode.getId(), obmap.convertValue(model, Map.class));
}

Ответ 4

    @Bean
public RedisTemplate<String, Object> redisTemplate() {
    final RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
    template.setConnectionFactory(jedisConnectionFactory());
    template.setKeySerializer(new StringRedisSerializer());
    template.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
    template.afterPropertiesSet();
    return template;
}