2015-01-12 16 views
10

Io uso della cache primavera con questo metodo che restituisce il valore interrogato come JSON:Come avere la cache primavera memorizzare il responseBody e non l'oggetto intermediario

@RequestMapping("/getById") 
@ResponseBody 
@Cacheable 
public HugeValue getHugeValueFromSlowFoo(@RequestParam(value = "id", defaultValue = "") String id) { 
    return Foo.getById(id); 
} 

Questo funziona bene e l'HugeValue-oggetto viene memorizzato nella cache (Hazelcast in questo caso). Voglio migliorare ulteriormente questo perché il tempo necessario per creare JSON da HugeValue è abbastanza alto. Posso dire al cache di primavera di memorizzare nella cache la versione JSON del mio oggetto?

Io uso Jackson con la Primavera Boot 1.2 e 4.1 Primavera

risposta

6

Senza sapere il vostro caso esatto utilizzo (non sto ancora permesso di aggiungere commenti per chiedere purtroppo), cerco di dare un breve riassunto sulle idee Ho in mente. Tutti presuppongono che tu usi Jackson per la mappatura JSON e almeno Spring 3.1.

Non esiste alcuna funzione enableResponseBodyCaching in SpringMVC, per quanto ne so.

Prima alternativa: Utilizzare la cache http perché sembra proprio che si desideri memorizzare l'intera risposta http. Primavera offre un modo dritto in avanti di configurazione globale:

<mvc:interceptors> 
    <bean id="webContentInterceptor" 
      class="org.springframework.web.servlet.mvc.WebContentInterceptor"> 
     <property name="cacheSeconds" value="0"/> 
     <property name="useExpiresHeader" value="true"/> 
     <property name="useCacheControlHeader" value="true"/> 
     <property name="useCacheControlNoStore" value="true"/> 
    </bean> 
</mvc:interceptors> 

Se si desidera controllare questo per controller, ereditano dalla primavera AbstractController e impostare la proprietà cacheSeconds secondo i javadoc.

La vera potenza del caching http viene fornito con un proxy http davanti al server, ovviamente.

seconda idea: implementare la propria sottoclasse di MappingJackson2HttpMessageConverter. In writeInternal() è possibile aggiungere una logica che accede a una cache per recuperare una versione già mappata invece di mappare l'oggetto di input. Questo approccio significa che dovrai raggiungere i tuoi servizi per recuperare l'oggetto java dietro lo stream di Json. Se per te va bene, perché a volte c'è anche il caching, questo approccio vale la pena di provarlo.

Terza idea: Effettua il mapping JSON da solo in un servizio wrapper dedicato che fornisce stringhe/flussi json non elaborati. È possibile iniettare facilmente il mappatore Jackson (nome classe ObjectMapper) e ottenere il controllo completo sulla mappatura. Annotando questo servizio, è possibile memorizzare nella cache i risultati. Nel tuo controller fornisci solo ResponseEntity del tipo che vuoi usare (stringa o flusso). Ciò impedirebbe anche un accesso di servizio più approfondito se è presente un risultato memorizzato nella cache.

Modifica: Probabilmente il MappingJackson2JsonView potrebbe anche essere utile. Ad essere onesti, non ho mai lavorato prima, quindi non posso davvero dire qualcosa sul suo utilizzo.

La speranza che aiuta e/o dà ispirazione! Cheers

+0

Grazie per le risposte approfondite e le grandi alternative. Aspetterò un po 'più a lungo se arrivano altre risposte, ma per ora mi piacciono tutte le alternative che descrivi e la terza idea sembra adattarsi anche se c'è del lavoro da fare per implementare questo. Quindi la pigrizia è l'unica ragione per me per aspettare una possibile quarta risposta che potrebbe richiedere meno lavoro ;-). Una cache del browser non è ciò che voglio perché ho migliaia di utenti che riceveranno lo stesso risultato e la cache del browser non funzionerebbe in modo perfetto perché HugeValue avrebbe bisogno di essere recuperato e jsonificato per ogni utente. – Marged

+0

La configurazione di WebContentInterceptor dice in realtà al client no di memorizzare nella cache la risposta ... –

1

Penso che questo potrebbe funzionare.

public interface HugeValueService{ 
    public String getHugeValueFromSlowFoo(String id); 
} 

public class HugeValueServiceImpl implements HugeValueService{ 
    @Cacheable 
    public String getHugeValueFromSlowFoo(String id) { 
     return Foo.getById(id); 
    } 
} 

Your Class 
---------- 
@RequestMapping("/getById") 
@ResponseBody 
public HugeValue getHugeValueFromSlowFoo(@RequestParam(value = "id", defaultValue = "") String id) { 
    return hugeValueService.getHugeValueFromSlowFoo(id); 
} 

Buona fortuna !!!

1

Cache the json e inserirlo nella risposta manualmente.

public void getHugeValueFromSlowFoo(@RequestParam(value = "id", defaultValue = "") String id, ServletResponse resp) 
{ 
    String jsonSerializedHugeValue = Bar.getById(id); // serialize manually with ObjectMapper 
    resp.getWriter().write(jsonSerializedHugeValue); 
    resp.setContentType("application/json"); 
    resp.flushBuffer(); 
} 
+0

Questo funziona, ma non è molto "Stile di avvio". Che non ho menzionato come prerequisito ;-) – Marged

+0

Anche se non comunemente usato (e correttamente, poiché non è necessario la maggior parte del tempo) è un codice sorgente e molla appropriato. È anche pulito, ovvio e ben leggibile. – Dariusz