如何让 spring 缓存存储 ResponseBody 而不是中间对象
How to have spring cache store the ResponseBody and not the intermediary object
我使用 spring 缓存与此方法 returns 查询值作为 JSON:
@RequestMapping("/getById")
@ResponseBody
@Cacheable
public HugeValue getHugeValueFromSlowFoo( @RequestParam(value = "id", defaultValue = "") String id ) {
return Foo.getById( id );
}
这工作正常并且 HugeValue 对象存储在缓存中(在本例中为 Hazelcast)。我想进一步改进这一点,因为从 HugeValue 创建 JSON 所花费的时间非常长。
我可以告诉 spring 缓存缓存我的对象的 JSON 化版本吗?
我将 Jackson 与 Spring Boot 1.2 和 Spring 4.1
一起使用
在不真正了解您的确切用例的情况下(不幸的是,我还不允许添加评论来提问),我尝试对我的想法进行简短的总结。他们都假设您使用 Jackson 进行 json 映射,并且至少 Spring 3.1.
据我所知,SpringMVC 中没有 enableResponseBodyCaching 功能。
第一个备选方案: 使用 http 缓存,因为您似乎真的想缓存整个 http 响应。 Spring 提供了一种直接的全局配置方式:
<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>
如果你想控制每个控制器,继承自 Spring AbstractController 并根据 javaDoc 设置 cacheSeconds 属性。
http 缓存的真正威力当然是在您的服务器前面有一个 http 代理。
第二个想法:实现你自己的 MappingJackson2HttpMessageConverter 的子class。在 writeInternal()
中,您可以添加一些逻辑来访问缓存以检索已映射的版本,而不是映射输入对象。这种方法意味着您将点击服务以检索 Json 流后面的 java 对象。如果这对您来说没问题,因为在某些时候也有缓存,那么恕我直言,这种方法值得一试。
第三个想法: 在提供原始 json strings/streams 的专用包装器服务中自行完成 json 映射。您可以轻松地注入 Jackson 映射器(class 名称 ObjectMapper)并获得对映射的完全控制。然后注释此服务允许您缓存结果。在您的控制器中,您只需提供您希望使用的相应类型(字符串或某些流)的 ResponseEntity。如果存在缓存结果,这甚至会阻止更深入的服务访问。
编辑:可能 MappingJackson2JsonView 也可以派上用场。老实说,我以前从未使用过它,所以我不能真正说出它的用法。
希望对您有所帮助 and/or 给予启发!
干杯
我认为这可行。
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);
}
祝你好运!!!
缓存 json 并手动将其放入响应中。
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();
}
我使用 spring 缓存与此方法 returns 查询值作为 JSON:
@RequestMapping("/getById")
@ResponseBody
@Cacheable
public HugeValue getHugeValueFromSlowFoo( @RequestParam(value = "id", defaultValue = "") String id ) {
return Foo.getById( id );
}
这工作正常并且 HugeValue 对象存储在缓存中(在本例中为 Hazelcast)。我想进一步改进这一点,因为从 HugeValue 创建 JSON 所花费的时间非常长。 我可以告诉 spring 缓存缓存我的对象的 JSON 化版本吗?
我将 Jackson 与 Spring Boot 1.2 和 Spring 4.1
一起使用在不真正了解您的确切用例的情况下(不幸的是,我还不允许添加评论来提问),我尝试对我的想法进行简短的总结。他们都假设您使用 Jackson 进行 json 映射,并且至少 Spring 3.1.
据我所知,SpringMVC 中没有 enableResponseBodyCaching 功能。
第一个备选方案: 使用 http 缓存,因为您似乎真的想缓存整个 http 响应。 Spring 提供了一种直接的全局配置方式:
<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>
如果你想控制每个控制器,继承自 Spring AbstractController 并根据 javaDoc 设置 cacheSeconds 属性。
http 缓存的真正威力当然是在您的服务器前面有一个 http 代理。
第二个想法:实现你自己的 MappingJackson2HttpMessageConverter 的子class。在 writeInternal()
中,您可以添加一些逻辑来访问缓存以检索已映射的版本,而不是映射输入对象。这种方法意味着您将点击服务以检索 Json 流后面的 java 对象。如果这对您来说没问题,因为在某些时候也有缓存,那么恕我直言,这种方法值得一试。
第三个想法: 在提供原始 json strings/streams 的专用包装器服务中自行完成 json 映射。您可以轻松地注入 Jackson 映射器(class 名称 ObjectMapper)并获得对映射的完全控制。然后注释此服务允许您缓存结果。在您的控制器中,您只需提供您希望使用的相应类型(字符串或某些流)的 ResponseEntity。如果存在缓存结果,这甚至会阻止更深入的服务访问。
编辑:可能 MappingJackson2JsonView 也可以派上用场。老实说,我以前从未使用过它,所以我不能真正说出它的用法。
希望对您有所帮助 and/or 给予启发! 干杯
我认为这可行。
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);
}
祝你好运!!!
缓存 json 并手动将其放入响应中。
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();
}