【Spring Boot学习总结】9.Web开发-自动配置与静态资源配置(源码分析)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013517797/article/details/82051343

上一篇我们讲解了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

猜你喜欢

转载自blog.csdn.net/u013517797/article/details/82051343