Spring静态资源处理多种方式(<mvc:default-servlet-handler>)

Spring静态资源处理多种方式(<mvc:default-servlet-handler>)

可以基于xml或纯java配置, 源码分析基于Spring 5.2.5, 为了简洁会省去部分源码.

简单来说DispatcherServlet接收了所有请求(“/”), 交由某个映射器来处理静态资源的请求(forward到tomcat默认servlet直接resource写入)

方式一:<mvc:default-servlet-handler>

// 所有<mvc:xxx>由MvcNamespaceHandler管理,从该类获取对应处理类
class DefaultServletHandlerBeanDefinitionParser implements BeanDefinitionParser {
    
    //...只剩下关键代码
    String defaultServletName = element.getAttribute("default-servlet-name");
    RootBeanDefinition defaultServletHandlerDef = new RootBeanDefinition(DefaultServletHttpRequestHandler.class);
    //...
    String defaultServletHandlerName = parserContext.getReaderContext().generateBeanName(defaultServletHandlerDef);
    //...
    Map<String, String> urlMap = new ManagedMap<>();
    urlMap.put("/**", defaultServletHandlerName);

    RootBeanDefinition handlerMappingDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class);
    handlerMappingDef.getPropertyValues().add("urlMap", urlMap);
    //....
}

从中可以知道注册了两个bean, SimpleUrlHandlerMapping(HandlerMapping)和**DefaultServletHttpRequestHandler**(最终变成该映射器的handler).

从上面第11行 /** 可知, SimpleUrlHandlerMapping会在DispatcherServlet中拦截所有请求(一般位于映射器列表末尾,起到“保底”作用), 最终交由DefaultServletHttpRequestHandler#handleRequest处理, forward到tomcat默认servlet(下面第7行).

// 可以看出只是单纯转发, 最终还是交由tomcat等容器的默认servlet处理(默认的servlet="defalut")
// 该servlet名字可自行指定, <mvc:default-servlet-handler default-servlet-name="">
public class DefaultServletHttpRequestHandler implements HttpRequestHandler, ServletContextAware {
    @Override
	public void handleRequest(HttpServletRequest request, HttpServletResponse response) {
		RequestDispatcher rd = this.servletContext.getNamedDispatcher(this.defaultServletName);
		rd.forward(request, response);
	}
}

要注意的是拦截器的依然会生效(先执行HandlerInterceptor#preHandle, 后执行该代码)

方式二:<mvc:resources>

<mvc:resources mapping="/images/**" location="/WEB-INF/images"/>

参考上面,从ResourcesBeanDefinitionParser得知注册的关键bean为,SimpleUrlHandlerMappingResourceHttpRequestHandler.

该标签做的事情与上面类似, 不同的是可以自定义资源映射路径, 处理也不是简单forward, 是由Spring MVC自己处理Resource(可以缓存等).

public class ResourceHttpRequestHandler implements HttpRequestHandler {
    public void handleRequest(HttpServletRequest request, HttpServletResponse response) {
		Resource resource = getResource(request);
        //...写入response
        this.resourceHttpMessageConverter.write(resource, mediaType, outputMessage);
    }
}

两个标签可以同时存在, 最终会生成多个映射器(SimpleUrlHandlerMapping), 注意顺序即可


以下是纯Java配置, 上面两种方式也可以配置成@Bean的形式

方式三: WebMvcConfigurer

该方式与方式一,二创建的bean的对应

@EnableWebMvc, 简单来说该注解引入的类DelegatingWebMvcConfiguration, 最终会调用WebMvcConfigurer的方法

(具体参考另外一篇文章:<mvc:annotation-driven> 和 @EnableWebMvc 解析)

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        // 默认静态资源处理,对应方式一, (DefaultServletHandlerConfigurer#buildHandlerMapping)
        configurer.enable();
    }
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // 方式二, (源码参考:ResourceHandlerRegistry#getHandlerMapping)
        registry.addResourceHandler("/images/**").addResourceLocations("/images/");
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值