一、HTTP緩存java
HTTP緩存能夠顯著提升web應用程序的性能。HTTP緩存圍繞着Cache-Control響應頭和後續的條件請求頭(如Last-Modified
和ETag)進行。Cache-Control建議私有(例如,瀏覽器)和公共(例如,代理)緩存如何緩存和重用響應。ETag頭用於發出條件請求,若是內容沒有更改,則可能致使304(NOT_MODIFIED)沒有正文。ETag能夠看做是Last-Modified文件的更復雜的繼承者。jquery
本節講 Spring WebFlux中可用的與HTTP緩存相關的方式。web
1.一、CacheControlspring
CacheControl
支持配置與Cache-Control標頭相關的設置,並在許多位置被接受爲參數:sql
Controllers編程
靜態Resourcesjson
雖然RFC 7234描述了緩存Cache-Control頭的全部可能的指令,但CacheControl
類型採用了面向用例的方法,重點關注常見場景,以下例所示:api
//緩存一小時-「Cache-Control: max-age=3600」CacheControl ccCacheOneHour = CacheControl.maxAge(1, TimeUnit.HOURS);
// 防止緩存 - "Cache-Control: no-store"CacheControl ccNoStore = CacheControl.noStore();
// 在公共緩存和私有緩存中緩存10天,公共緩存不該轉換響應// "Cache-Control: max-age=864000, public, no-transform"CacheControl ccCustom = CacheControl.maxAge(10, TimeUnit.DAYS).noTransform().cachePublic();
1.二、Controllers瀏覽器
控制器能夠添加對HTTP緩存的支持。建議這樣作,由於在將資源與條件請求頭進行比較以前,須要計算資源的lastModified
或ETag
值。控制器能夠向ResponseEntity添加ETag
和Cache-Control設置,以下例所示:緩存
public ResponseEntity<Book> showBook( Long id) {
Book book = findBook(id); String version = book.getVersion();
return ResponseEntity .ok() .cacheControl(CacheControl.maxAge(30, TimeUnit.DAYS)) .eTag(version) // lastModified也可用 .body(book);}
若是與條件請求頭的比較代表內容沒有更改,則前面的示例發送一個304(NOT_MODIFIED)響應,該響應的主體爲空。不然,ETag
和Cache-Control頭將被添加到響應中。
還能夠在控制器中對條件請求頭進行檢查,以下例所示:
public String myHandleMethod(ServerWebExchange exchange, Model model) {
long eTag = ... //應用程序指定計算。
if (exchange.checkNotModified(eTag)) { return null; //響應已設置爲304(未修改)。無需進一步處理。 }
model.addAttribute(...); //繼續請求處理 return "myViewName";}
根據eTag
值、lastModified
值或二者檢查條件請求有三種變體。對於有條件的GET
和HEAD
請求,能夠將響應設置爲304(NOT_MODIFIED)。對於條件POST、PUT和DELETE,能夠將響應設置爲409(PRECONDITION_FAILED),以防止併發修改。
1.三、靜態Resources
你應該爲靜態資源提供緩存控件和條件響應頭,以得到最佳性能。
public class WebConfig implements WebFluxConfigurer {
public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/resources/**") .addResourceLocations("/public", "classpath:/static/") .setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS)); }
}
二、WebFlux 配置
WebFlux ava配置聲明瞭使用帶註解的控制器或functional endpoints處理請求所需的組件,並提供了一個API來定製配置。這意味着你不須要理解由Java配置建立的底層bean。可是,若是想了解它們,能夠在WebFluxConfigurationSupport
中看到它們,或者閱讀有關它們在特殊Bean類型中的更多信息。
對於配置API中不可用的更高級自定義,能夠經過高級配置模式得到對配置的徹底控制。
2.一、啓用WebFlux配置
能夠在Java配置中使用@EnableWebFlux註解,以下例所示:
public class WebConfig {}
前面的示例註冊了許多Spring WebFlux bean,並對JSON、XML等classpath - 上可用的依賴關係進行了調整。
2.二、WebFlux配置API
在Java配置中,能夠實現WebFluxConfigurer
接口,以下例所示:
public class WebConfig implements WebFluxConfigurer {
// 實現配置方法。。。}
2.三、轉換,格式化
默認狀況下,安裝了Number
和Date
類型的格式化程序,包括對@NumberFormat和@DateTimeFormat註解的支持。若是classpath中存在Joda時間,則還安裝了對Joda時間格式庫的徹底支持。
如下示例顯示如何註冊自定義格式設置程序和轉換器:
public class WebConfig implements WebFluxConfigurer {
public void addFormatters(FormatterRegistry registry) { // ... }
}
有關什麼時候使用 FormatterRegistrar
實現的更多信息,請查看 FormatterRegistrar
SPI和FormattingConversionServiceFactoryBean
。
2.四、驗證Validation
默認狀況下,若是類路徑上存在Bean驗證(例如,Hibernate驗證器),則LocalValidatorFactoryBean
註冊爲全局驗證器,以便與@Valid和Validated
在@Controller方法參數一塊兒使用。
在Java配置中,能夠自定義全局Validator
實例,以下例所示:
public class WebConfig implements WebFluxConfigurer {
public Validator getValidator(); { // ... }
}
還能夠在本地註冊如下驗證程序實現:
public class MyController {
protected void initBinder(WebDataBinder binder) { binder.addValidators(new FooValidator()); }
}
若是須要在某個地方注入LocalValidatorFactoryBean
,請建立一個bean並用@Primary標記,以免與MVC配置中聲明的bean衝突。
2.五、Content Type解析程序
你能夠配置Spring WebFlux如何根據請求爲@Controller實例肯定請求的媒體類型。默認狀況下,只選中Accept
頭,但也能夠啓用基於查詢參數的策略。
如下示例顯示如何自定義請求的content type解析:
public class WebConfig implements WebFluxConfigurer {
public void configureContentTypeResolver(RequestedContentTypeResolverBuilder builder) { // ... }}
2.六、HTTP消息編解碼器
如下示例顯示如何自定義請求和響應正文的讀寫方式:
public class WebConfig implements WebFluxConfigurer {
public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) { // ... }}
ServerCodecConfigurer
提供了一組默認的讀卡器和寫入器。你可使用它添加更多的讀卡器和編寫器,自定義默認的,或者徹底替換默認的。
對於jacksonjson和XML,考慮使用 Jackson2ObjectMapperBuilder
,它使用如下屬性定製Jackson2ObjectMapperBuilder:
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
被禁用。MapperFeature.DEFAULT_VIEW_INCLUSION
被禁用。
若是在類路徑上檢測到如下已知模塊,它還會自動註冊它們:
jackson-datatype-joda
: 支持Joda時間類型。jackson-datatype-jsr310
: 支持Java8日期和時間API類型。jackson-datatype-jdk8
: 支持其餘Java8類型,如Optional。jackson-module-kotlin
:支持Kotlin類和數據類。
2.七、視圖解析器
如下示例顯示如何配置視圖:
Configurationpublic class WebConfig implements WebFluxConfigurer {
public void configureViewResolvers(ViewResolverRegistry registry) { // ... }}
ViewResolverRegistry
爲Spring框架集成的視圖技術提供了快捷方式。如下示例使用FreeMarker(這還須要配置底層的FreeMarker視圖技術):
public class WebConfig implements WebFluxConfigurer {
public void configureViewResolvers(ViewResolverRegistry registry) { registry.freeMarker(); }
// 配置Freemarker...
public FreeMarkerConfigurer freeMarkerConfigurer() { FreeMarkerConfigurer configurer = new FreeMarkerConfigurer(); configurer.setTemplateLoaderPath("classpath:/templates"); return configurer; }}
還能夠插入任何ViewResolver
實現,以下例所示:
public class WebConfig implements WebFluxConfigurer {
public void configureViewResolvers(ViewResolverRegistry registry) { ViewResolver resolver = ... ; registry.viewResolver(resolver); }}
爲了支持內容協商和經過視圖解析(除了HTML)呈現其餘格式,你能夠基於HttpMessageWriterView
實現配置一個或多個默認視圖,該實現spring-web的任何可用編解碼器。下面的示例演示如何執行此操做:
public class WebConfig implements WebFluxConfigurer {
public void configureViewResolvers(ViewResolverRegistry registry) { registry.freeMarker();
Jackson2JsonEncoder encoder = new Jackson2JsonEncoder(); registry.defaultViews(new HttpMessageWriterView(encoder)); }
// ...}
2.八、靜態資源
此方式提供了一種從基於資源的位置列表中提供靜態資源的方便方法。
在下一個例子中,給定一個以/resources開頭的請求,相對路徑用於查找和服務類路徑上相對於/static的靜態資源。資源的有效期爲一年,以確保最大限度地利用瀏覽器緩存並減小瀏覽器發出的HTTP請求。Last-Modified頭也被計算,若是存在,則返回304狀態代碼。如下列表顯示了示例:
public class WebConfig implements WebFluxConfigurer {
public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/resources/**") .addResourceLocations("/public", "classpath:/static/") .setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS)); }
}
資源處理程序還支持一系列ResourceResolver
實現和ResourceTransformer
實現,它們可用於建立一個工具鏈,用於處理優化的資源。
能夠根據VersionResourceResolver
或其餘信息計算的MD5哈希值,對版本化的資源url使用versionresolver。ContentVersionStrategy
(md5hash)是一個很好的選擇,但有一些明顯的例外(好比與模塊加載器一塊兒使用的JavaScript資源)。
如下示例顯示如何在Java配置中使用VersionResourceResolver
:
public class WebConfig implements WebFluxConfigurer {
public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/resources/**") .addResourceLocations("/public/") .resourceChain(true) .addResolver(new VersionResourceResolver().addContentVersionStrategy("/**")); }
}
可使用ResourceUrlProvider
重寫URL並應用完整的解析器和轉換器鏈(例如,插入版本)。WebFlux配置提供了一個ResourceUrlProvider
,以即可以將其注入到其餘配置中。
與Spring MVC不一樣,目前在WebFlux中,沒有辦法透明地重寫靜態資源url,由於沒有視圖技術能夠利用非阻塞的解析器和轉換器鏈。當只提供本地資源時,解決方法是直接使用ResourceUrlProvider
(例如,經過自定義元素)和block。
請注意,當同時使用EncodedResourceResolver
(例如,Gzip、Brotli encoded)和VersionedResourceResolver時,必須按順序註冊它們,以確保基於內容的版本始終基於未編碼的文件可靠地計算。
WebJars也經過WebJarsResourceResolver
來支持,當org.webjars:webjars-locator-core庫位於類路徑上。解析器能夠重寫url以包含jar的版本,還能夠與沒有版本 - 的傳入url相匹配,例如從/jquery/1.2.0/jquery.min.js至/jquery/jquery.min.js。
2.九、路徑匹配
能夠自定義與路徑匹配相關的方式。如下示例顯示如何使用PathMatchConfigurer:
public class WebConfig implements WebFluxConfigurer {
public void configurePathMatch(PathMatchConfigurer configurer) { configurer .setUseCaseSensitiveMatch(true) .setUseTrailingSlashMatch(false) .addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController.class)); }}
Spring WebFlux依賴一個名爲RequestPath
的請求路徑解析表示來訪問解碼的路徑段值,去掉分號內容(即路徑或矩陣變量)。這意味着,與Spring MVC不一樣,您不須要指示是否解碼請求路徑,也不須要出於路徑匹配的目的刪除分號內容。Spring WebFlux也不支持後綴模式匹配,與Spring MVC不一樣,建議不要依賴它。
2.十、高級配置模式
@EnableWebFlux導入DelegatingWebFluxConfiguration
配置,該配置:
爲WebFlux應用程序提供默認的Spring配置
檢測並委派到
WebFluxConfigurer
實現以自定義該配置。
對於高級模式,能夠刪除@EnableWebFlux並直接從DelegatingWebFluxConfiguration
擴展,而不是實現WebFluxConfigurer,以下例所示:
public class WebConfig extends DelegatingWebFluxConfiguration {
// ...}
能夠在WebConfig中保留現有方法,但如今還能夠覆蓋基類中的bean聲明,而且在類路徑上仍然有任意數量的其餘WebMvcConfigurer
實現。
目前,Spring WebFlux不支持Netty的HTTP/2。也不支持以編程方式將資源推送到客戶端。
歡迎關注和轉發Spring中文社區(加微信羣,能夠關注後加我微信):
本文分享自微信公衆號 - Spring中文社區(gh_81d233bb13a4)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。