成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

SpringBoot靜態資源配置原理詳解

開發 前端
使用來自Spring MVC的ResourceHttpRequestHandler,因此可以通過添加自己的WebMvcConfigurer并覆蓋addResourceHandlers方法來修改該行為。

環境:Springboot2.7.10

默認情況下,Spring Boot從類路徑中的/static(或/public或/resources或/META-INF/resources)目錄或ServletContext的根目錄中提供靜態內容。它使用來自Spring MVC的ResourceHttpRequestHandler,因此可以通過添加自己的WebMvcConfigurer并覆蓋addResourceHandlers方法來修改該行為。

默認情況下,資源映射在/**上,但是你可以使用spring.mvc.static-path-pattern配置屬性進行修改。例如,將所有資源重新定位到/resources/**可以實現如下:

默認靜態資源路徑

spring:
web:
resources:
static-locations:
- classpath:/META-INF/resources/
- classpath:/resources/
- classpath:/static/
- classpath:/public/

目錄結構如下:

圖片

默認訪問路徑:??http://localhost:8080/xxx.yy??

修改訪問路徑?

spring:
mvc:
static-path-pattern: /res/**

如上修改后訪問路徑:
?http://localhost:8080/res/xxx.yy??

注意:如果你使用的是舊版本Springboot,這里的靜態資源配置是spring.resources.static-locations

添加靜態資源路徑

spring:
web:
resources:
static-locations:
- classpath:/META-INF/resources/
- classpath:/resources/
- classpath:/static/
- classpath:/public/
- file:///D:/images/

上面的:file:///D:/images/

編程方式配置

@Configuration
public class WebConfig implements WebMvcConfigurer {


@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("file:///d:/images/") ;
registry.addResourceHandler("/h5/**").addResourceLocations("file:///d:/h5/") ;
}

}

上面配置了2個文件系統的資源目錄,分別以:/static/**,/h5/**路徑進行訪問

訪問:
?http://localhost:8080/static/xxx.yy,http://localhost:8080/h5/xxx。??

WebJars靜態資源

除了前面提到的“標準”靜態資源位置之外,Webjars內容還有一個特殊情況。任何路徑在/webjars/**中的資源都是從jar文件中提供的,前提是它們以webjars格式打包的。

如果你的應用程序打包為jar,請不要使用src/main/webapp目錄。盡管這個目錄是一個常見的標準,但它只適用于war打包,并且如果你生成一個jar,它會被大多數構建工具默默地忽略。

Spring Boot還支持Spring MVC提供的高級資源處理功能,允許使用緩存破壞靜態資源或為Webjars使用版本不可知的URL等用例。

要為Webjars使用版本不可知的url,請添加webjars-locator-core依賴項。然后聲明你的webjar。以jQuery為例,添加"/webjars/jQuery/jQuery .min.js"會得到"
/webjars/jQuery/x.y.z/jQuery .min.js",其中x.y.z是webjar版本。

為了使用緩存破壞,下面的配置為所有靜態資源配置緩存破壞解決方案,有效地在url中添加內容哈希,例如<link href="
/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>:?

spring:
web:
resources:
chain:
strategy:
content:
enabled: true
paths: "/**"

靜態資源訪問原理

SpringMVC核心組件配置:?

@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
// 注入當前環境中所有的WebMvcConfigurer類型的Bean
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
// 添加到上面的WebMvcConfigurerComposite中
this.configurers.addWebMvcConfigurers(configurers);
}
}
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
// 調用WebMvcConfigurerComposite#addResourceHandlers方法,該方法內部
// 遍歷所有的WebMvcConfigurer分別調用addResourceHandlers方法
this.configurers.addResourceHandlers(registry);
}
}
class WebMvcConfigurerComposite implements WebMvcConfigurer {
private final List<WebMvcConfigurer> delegates = new ArrayList<>();
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
for (WebMvcConfigurer delegate : this.delegates) {
delegate.addResourceHandlers(registry);
}
}
}

Spring提供的一個WebMvcConfigurer實現?

public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// ...
// addResourceHandler注冊資源實例
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
// getStaticPathPattern獲取配置文件中spring.mvc.staticPathPattern屬性值
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
// getStaticLocations獲取配置文件中spring.web.resources.staticLocations屬性值
// 該方法調用后就會將資源訪問路徑與具體資源路徑進行關聯
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, SERVLET_LOCATION);
registration.addResourceLocations(resource);
}
});
}
private void addResourceHandler(ResourceHandlerRegistry registry, String pattern, String... locations) {
addResourceHandler(registry, pattern, (registration) -> registration.addResourceLocations(locations));
}
private void addResourceHandler(ResourceHandlerRegistry registry, String pattern, Consumer<ResourceHandlerRegistration> customizer) {
if (registry.hasMappingForPattern(pattern)) {
return;
}
// 創建并獲取資源訪問模式的的實例
ResourceHandlerRegistration registration = registry.addResourceHandler(pattern);
// 自定義配置
customizer.accept(registration);
// 緩存設置
registration.setCachePeriod(getSeconds(this.resourceProperties.getCache().getPeriod()));
registration.setCacheControl(this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl());
registration.setUseLastModified(this.resourceProperties.getCache().isUseLastModified());
customizeResourceHandlerRegistration(registration);
}
}

ResourceHandlerRegistry?

public class ResourceHandlerRegistry {
private final List<ResourceHandlerRegistration> registrations = new ArrayList<>();
// 為每一種資源創建ResourceHandlerRegistration實例,添加到List集合中
public ResourceHandlerRegistration addResourceHandler(String... pathPatterns) {
ResourceHandlerRegistration registration = new ResourceHandlerRegistration(pathPatterns);
this.registrations.add(registration);
return registration;
}
}

通過上面的源碼我們只看到收集容器中所有WebMvcConfigurer類型的Bean,然后分別調用重寫的addResourceHandlers方法接著為每一種資源訪問路徑/xxx創建對應的ResourceHandlerRegistration實例,并且將這些實例添加到ResourceHandlerRegistry中。

這里有2個疑問:

  1. ResourceHandlerRegistry是如何創建的
  2. 當訪問這些靜態資源時對應的HandlerMapping及Adapter又是誰如何與上面的ResourceHandlerRegistration關聯的。

ResourceHandlerRegistry創建

上面的
DelegatingWebMvcConfiguration配置類繼承WebMvcConfigurationSupport,該父類中有如下方法:?

public class WebMvcConfigurationSupport {
// 該Bean是一個HandlerMapping(這是個接口),用來確定當前請求對應的處理器類
@Bean
public HandlerMapping resourceHandlerMapping(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
PathMatchConfigurer pathConfig = getPathMatchConfigurer();
// 這里創建了資源注冊器類
ResourceHandlerRegistry registry = new ResourceHandlerRegistry(this.applicationContext, this.servletContext, contentNegotiationManager, pathConfig.getUrlPathHelper());
// 添加注冊靜態資源,該訪問正好被子類DelegatingWebMvcConfiguration重寫了
// 而 在上面源碼看到,子類就是遍歷了容器中所有的WebMvcConfigurer對應的addResourceHandlers方法
// 到這里你就清楚了靜態資源的注冊入口,接下來就是這些靜態資源對應是如何與HandlerMapping關聯的
addResourceHandlers(registry);
// 獲取HandlerMapping對象
AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
// ...
return handlerMapping;
}
}

通過ResourceHandlerRegistry獲取HandlerMapping對象?

public class ResourceHandlerRegistry {
protected AbstractHandlerMapping getHandlerMapping() {
// 如果沒有配置靜態資源,那么就沒有必要注冊HandlerMapping了,直接返回null
if (this.registrations.isEmpty()) {
return null;
}
Map<String, HttpRequestHandler> urlMap = new LinkedHashMap<>();
// 遍歷上面注冊的所有靜態資源對應的ResourceHandlerRegistration
for (ResourceHandlerRegistration registration : this.registrations) {
// 將ResourceHandlerRegistration對象轉換為ResourceHttpRequestHandler對象
ResourceHttpRequestHandler handler = getRequestHandler(registration);
for (String pathPattern : registration.getPathPatterns()) {
// 以配置的訪問路徑為key,對應的ResourceHttpRequestHandler為處理句柄
// 當一個請求過來如果匹配了當前的模式,那么就會用對應的ResourceHttpRequestHandler對象進行處理
urlMap.put(pathPattern, handler);
}
}
return new SimpleUrlHandlerMapping(urlMap, this.order);
}
private ResourceHttpRequestHandler getRequestHandler(ResourceHandlerRegistration registration) {
// 獲取
ResourceHttpRequestHandler handler = registration.getRequestHandler();
handler.setServletContext(this.servletContext);
handler.setApplicationContext(this.applicationContext);
try {
// 執行初始化
handler.afterPropertiesSet();
}
return handler;
}
}
public class ResourceHandlerRegistration {
protected ResourceHttpRequestHandler getRequestHandler() {
// 創建對象
ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();
// ...
// 設置路徑
handler.setLocationValues(this.locationValues);
handler.setLocations(this.locationsResources);
if (this.cacheControl != null) {
handler.setCacheControl(this.cacheControl);
}
// ... 這里緩存設置
return handler;
}
}

ResourceHttpRequestHandler對應的HandlerAdapter對象?

public class HttpRequestHandlerAdapter implements HandlerAdapter {


@Override
public boolean supports(Object handler) {
// ResourceHttpRequestHandler實例HttpRequestHandler子類
return (handler instanceof HttpRequestHandler);
}


@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 直接調用ResourceHttpRequestHandler#handleRequest方法
((HttpRequestHandler) handler).handleRequest(request, response);
return null;
}
}


責任編輯:武曉燕 來源: 實戰案例錦集
相關推薦

2009-06-04 20:19:16

Eclipse插件Jinto資源配置

2022-04-19 16:09:53

數字化轉型數字經濟信息安全

2018-01-23 11:00:10

Hadoop3.0Yarn資源

2009-10-27 14:31:57

linux靜態路由

2022-12-19 08:00:00

SpringBootWeb開發

2010-12-12 21:58:00

半靜態語言動態語言靜態語言

2010-11-19 17:42:13

2024-11-06 09:54:58

SpringJava開發

2022-06-08 09:56:46

靜態鏈接Linux命令

2025-01-08 00:09:00

云平臺云計算管理

2025-02-27 14:01:50

2023-10-04 18:24:54

wpf動態資源

2009-12-09 11:04:14

浮動靜態路由配置

2023-09-07 08:39:39

copy屬性數據源

2019-09-03 15:36:58

ApacheTomcat配置

2020-07-08 13:46:27

ApacheTomcat配置

2025-02-27 00:10:19

2023-10-15 12:18:36

MPLS網絡

2023-07-20 10:04:37

底層路由配置

2018-12-18 14:37:26

Spark內存管理
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 成人av免费在线观看 | 日韩免费在线视频 | 成人免费在线播放视频 | 一区二区在线观看免费视频 | 欧美成人激情 | 亚洲成人av | 在线观看av网站 | 中文字幕亚洲欧美 | 色桃网 | 鲁视频 | 婷婷综合色 | 蜜月aⅴ国产精品 | 欧美日韩国产一区二区三区 | 天天操网 | 亚洲高清视频在线观看 | 亚洲另类春色偷拍在线观看 | 精品久久久久久久 | av天天看 | 精品国产91| 久久久久国产一区二区三区四区 | 黑人性hd| 91极品视频 | 能看的av网站 | 日韩欧美不卡 | 一区二区久久电影 | 欧美日韩在线观看一区 | 国产做爰 | 伊人网综合在线观看 | 欧美亚洲一区二区三区 | 日韩精品一区二区在线观看 | 亚洲福利在线观看 | www.色综合| av日韩在线播放 | 亚洲成人av一区二区 | 一区二区三区久久久 | 久久精品亚洲 | 久久中文字幕电影 | 久久久亚洲一区 | 岛国在线免费观看 | 精品久久一区二区三区 | 国产精品中文字幕在线观看 |