上一篇我們講解了Spring Boot的自動配置的機制以及原理,本篇我們來介紹使用Spring Boot進行Web開發時,Spring Boot是如何為我們提供強大的Web開發依賴的支援的。
一、Web開發環境自動配置
上一篇講到Spring Boot的自動配置環節,提到大部分的常用開發架構Spring Boot都幫我們做好了自動配置,而Web開發也不例外。在Spring Boot中,Web開發的自動配置類為:org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration。
我們在樣例工程的依賴中找到WebMvcAutoConfiguration的依賴:
然後在下面的 包下,可以找到WebMvcAutoConfiguration類:
我們打開WebMvcAutoConfiguration類的源碼,可以看到該類上面的注解:
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,
WebMvcConfigurerAdapter.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
//......
}
其中我們可以看到“@ConditionalOnClass”注解,這個就是我們前面提到的條件注解,隻要滿足後面的class存在的條件,該類才會加載生效。這裡就是需要擁有JavaWeb的“Servlet”類,Spring MVC的“DispatcherServlet”類以及“WebMvcConfigurerAdapter”擴充卡類,才會執行個體化該WebMvcAutoConfiguration的Web環境自動配置類。
然後我們再來看源碼中的httpPutFormContentFilter()方法:
@Bean
@ConditionalOnMissingBean(HttpPutFormContentFilter.class)
@ConditionalOnProperty(prefix = "spring.mvc.formcontent.putfilter", name = "enabled", matchIfMissing = true)
public OrderedHttpPutFormContentFilter httpPutFormContentFilter() {
return new OrderedHttpPutFormContentFilter();
}
其中包含一個“@ConditionalOnMissingBean”的注解,即是如我們沒有自己配置HttpPutFormContentFilter攔截器的話,才會幫我們自動配置該攔截器。
而在該類中還有大量的這種配置,感興趣的同學可以詳細的讀取其源碼。下面我們重點來看有關視圖解析器的自動配置源碼:
@Bean
@ConditionalOnMissingBean
public InternalResourceViewResolver defaultViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix(this.mvcProperties.getView().getPrefix());
resolver.setSuffix(this.mvcProperties.getView().getSuffix());
return resolver;
}
@Bean
@ConditionalOnBean(View.class)
@ConditionalOnMissingBean
public BeanNameViewResolver beanNameViewResolver() {
BeanNameViewResolver resolver = new BeanNameViewResolver();
resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);
return resolver;
}
defaultViewResolver是當沒有配置視圖解析器ViewResolver時(視圖解析器幫助我們渲染與使用者的互動視圖,如JSP頁面),用來加載預設的視圖解析器的配置方法。我們可以看到,在defaultViewResolver方法上面有注解“@Bean”,說明該方法傳回的類會作為一個Spring對象被執行個體化,加載至Spring容器中。而該方法傳回的類為“InternalResourceViewResolver”,這和我們在傳統的Spring MVC開發中在Spring配置檔案中配置的:
<!-- 内部資源視圖解析器-->
<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages"/>
<property name="suffix" value=".jsp"/>
</bean>
效果是一樣的。而Spring Boot在我們沒有配置視圖解析器的時候,就幫我們自動執行個體化“InternalResourceViewResolver”為我們的視圖解析器。
而其中的視圖字首(prefix)和視圖字尾(suffix)是從哪裡自動擷取的?從代碼中我們可以看到是從一個“mvcProperties”對象中取出的,而該對象的執行個體化包括配置的前字尾的值,使我們在搭建Spring Boot環境時,在全局配置檔案application.properties中配置的:
spring.mvc.view.prefix= # Spring MVC view prefix.
spring.mvc.view.suffix= # Spring MVC view suffix.
二、自動配置靜态資源
我們在之前的Spring Boot樣例工程中配置全局配置檔案application.properties:
server.port=8088
server.servlet-path=/
logging.level.org.springframework=DEBUG
然後在src/main/webapp和src/main/resources/images下分别放置一張圖檔:
然後啟動工程,在浏覽器中通路該圖檔1(http://localhost:8088/1.png):
可以看到圖檔被加載出來,而通路圖檔2(http://localhost:8088/images/3.png):
則不會被加載出來。這是為什麼呢?
其實原因很簡單,就是我們沒有為靜态資源配置加載路徑,導緻圖檔2加載不出來。而圖檔1能加載出來是因為預設的web開發中會預設配置webapp目錄的靜态資源可直接加載。
那麼,如何配置Spring Boot使得其可以加載除了webapp目錄以外的指定的靜态資源呢?
其實當我們沒有配置Spring MVC的靜态資源加載路徑時,Spring Boot會幫我們配置為“/**”,即相當于在application.properties中配置以下資訊:
spring.mvc.static-path-pattern=/**
spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpth:/public/
此時靜态資源的所有通路映射到以下目錄:
classpath:/static
classpath:/public
classpath:/resources
classpath:/META-INF/resources
Spring Boot 預設會挨個從/src/main/resources/目錄下的resources、static、public裡面找是否存在相應的資源,如果有則直接傳回。優先級順序為:META-INF/resources > resources > static > public。
這點我們也可以通過源碼證明。我們可以檢視spring-boot-autoconfigurejar包下的org.springframework.boot.autoconfigure.web包下的ResourceProperties類:
@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties implements ResourceLoaderAware {
private static final String[] SERVLET_RESOURCE_LOCATIONS = { "/" };
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
"classpath:/META-INF/resources/", "classpath:/resources/",
"classpath:/static/", "classpath:/public/" };
private static final String[] RESOURCE_LOCATIONS;
static {
RESOURCE_LOCATIONS = new String[CLASSPATH_RESOURCE_LOCATIONS.length
+ SERVLET_RESOURCE_LOCATIONS.length];
System.arraycopy(SERVLET_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS, 0,
SERVLET_RESOURCE_LOCATIONS.length);
System.arraycopy(CLASSPATH_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS,
SERVLET_RESOURCE_LOCATIONS.length, CLASSPATH_RESOURCE_LOCATIONS.length);
}
/**
* Locations of static resources. Defaults to classpath:[/META-INF/resources/,
* /resources/, /static/, /public/] plus context:/ (the root of the servlet context).
*/
private String[] staticLocations = RESOURCE_LOCATIONS;
//下面代碼省略
}
可以看到Spring Boot的自動配置中,預設指定了staticLocations的相關值。
而其實Spring Boot做的事情就是幫Spring MVC的ResourceHttpRequestHandler的ResourceResovlers設定了兩個參數:
(1)靜态資源請求響應路徑的配置(mapping)
(2)靜态資源根目錄的指定(location)
這個在傳統Spring MVC的配置檔案中是這麼配置的:
<mvc:resources location="/image" mapping="/**"/>
即spring.mvc.static-path-pattern和spring.resources.static-locations給Spring MVC中ResourceHttpRequestHandler的ResourceResovlers設定了resolveUrlPath和locations。
也就是說,我們剛剛如果在/src/main/resources/目錄下的下面建立META-INF/resources、resources、static、public檔案夾,在下面放檔案,也是可以直接通路的。
我們這裡不修改任何配置檔案,在在/src/main/resources/目錄下的下面建立META-INF/resources、resources、static、public檔案夾,在下面分别放一張圖檔:
重新開機應用通路圖檔3/4/5/6:
發現全部可以正常通路。說明Spring Boot為我們預設配置的就是這些。當我們需要通路images下的圖檔2的時候,可以在spring.resources.static-locations的最後配置images的路徑:
spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpth:/public/,classpth:/images/
然後重新開機應用,發現可以通路了:
如果我們想統一指定靜态資源的url請求路徑請求規則,就指定前面提到的那個spring.mvc.static-path-pattern配置,此時Spring Boot會在加載Spring MVC配置時指定
靜态資源請求響應的路徑。
我們這裡配置為:
spring.mvc.static-path-pattern=/static/**
也就是當我們在浏覽器中輸入“http://localhost:8080/static/”後直接跟靜态資源的名稱就可以通路(如http://localhost:8080/static/1.png),不加的話則不會比對任何資源,這就是為了統一通路資源規範。
當然除了在上面的application.properties中配置以外,也可以建立配置類,繼承WebMvcConfigurerAdapter類,并重寫addResourceHandlers方法,為其指定ResourceHandler以及ResourceLocations即可:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
public class MyWebAppConfigurer extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/images/");
super.addResourceHandlers(registry);
}
}
參考:
傳智播客《Spring Boot實戰與原理分析》視訊課程
(https://pan.baidu.com/s/1o9M2bGI 密碼:jxg8)
轉載請注明出處:https://blog.csdn.net/acmman/article/details/82051343