Springboot静态资源加载的简单探究
(不想看源代码可以直接跳到文末看结论)
1.
WebMvcAutoConfiguration类下:
注意到有addResourceHandlers方法,
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//无映射直接返回,logger记录
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
//registry是ResourceHandlerRegistry类的对象,由我们熟悉的ApplicationContext、ServletContext对象和可为null的ContentNegotiationManager和UrlPathHelper对象构造,详情见第2节 )
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");//自带的一个映射路径
//追踪源代码,可以找到:
//private String staticPathPattern = "/**";
//private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
"classpath:/resources/", "classpath:/static/", "classpath:/public/" };
//也就是说,这个方法的调用旨在将
//classpath:/META-INF/resources/","classpath:/resources/","classpath:/static/","classpath:/public/"
//四个路径下的静态资源映射到"/**"(全部目录)以供访问
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, SERVLET_LOCATION);
//private static final String SERVLET_LOCATION = "/";
registration.addResourceLocations(resource);
}
});
}
2.ResourceHandlerRegistry的部分源代码分析
/**
* Stores registrations of resource handlers for serving static resources such
* as images, css files and others through Spring MVC including setting cache
* headers optimized for efficient loading in a web browser. Resources can be
* served out of locations under web application root, from the classpath, and
* others.
*
* <p>To create a resource handler, use {@link #addResourceHandler(String...)}
* providing the URL path patterns for which the handler should be invoked to
* serve static resources (e.g. {@code "/resources/**"}).
*
* <p>Then use additional methods on the returned
* {@link ResourceHandlerRegistration} to add one or more locations from which
* to serve static content from (e.g. {{@code "/"},
* {@code "classpath:/META-INF/public-web-resources/"}}) or to specify a cache
* period for served resources.
*
* @author Rossen Stoyanchev
* @since 3.1
* @see DefaultServletHandlerConfigurer
*/
可以看出,该对象设计用于存储图片、css等静态资源的registration
ResourceHandlerRegistry的构造方法
/**
* Create a new resource handler registry for the given application context.
* @param applicationContext the Spring application context
* @param servletContext the corresponding Servlet context
*/
public ResourceHandlerRegistry(ApplicationContext applicationContext, ServletContext servletContext) {
this(applicationContext, servletContext, null);
}
/**
* Create a new resource handler registry for the given application context.
* @param applicationContext the Spring application context
* @param servletContext the corresponding Servlet context
* @param contentNegotiationManager the content negotiation manager to use
* @since 4.3
*/
public ResourceHandlerRegistry(ApplicationContext applicationContext, ServletContext servletContext,
@Nullable ContentNegotiationManager contentNegotiationManager) {
this(applicationContext, servletContext, contentNegotiationManager, null);
}
/**
* A variant of
* {@link #ResourceHandlerRegistry(ApplicationContext, ServletContext, ContentNegotiationManager)}
* that also accepts the {@link UrlPathHelper} used for mapping requests to static resources.
* @since 4.3.13
*/
public ResourceHandlerRegistry(ApplicationContext applicationContext, ServletContext servletContext,
@Nullable ContentNegotiationManager contentNegotiationManager, @Nullable UrlPathHelper pathHelper) {
Assert.notNull(applicationContext, "ApplicationContext is required");
this.applicationContext = applicationContext;
this.servletContext = servletContext;
this.contentNegotiationManager = contentNegotiationManager;
this.pathHelper = pathHelper;
}
事实上,对于所有可能的contentNegotiationManager和UrlPathHelper,方法内传入的值仍然是null
ResourceHandlerRegistry.addResourceHandler()方法:
public ResourceHandlerRegistration addResourceHandler(String... pathPatterns) {
ResourceHandlerRegistration registration = new ResourceHandlerRegistration(pathPatterns);
this.registrations.add(registration);
return registration;
}
对this.registrations.add()追踪,发现实际执行的方法为:
boolean addAll(Collection<? extends E> c);
/**
* Inserts all of the elements in the specified collection into this
* list at the specified position (optional operation). Shifts the
* element currently at that position (if any) and any subsequent
* elements to the right (increases their indices). The new elements
* will appear in this list in the order that they are returned by the
* specified collection's iterator. The behavior of this operation is
* undefined if the specified collection is modified while the
* operation is in progress. (Note that this will occur if the specified
* collection is this list, and it's nonempty.)
*
* @param index index at which to insert the first element from the
* specified collection
* @param c collection containing elements to be added to this list
* @return {@code true} if this list changed as a result of the call
* @throws UnsupportedOperationException if the {@code addAll} operation
* is not supported by this list
* @throws ClassCastException if the class of an element of the specified
* collection prevents it from being added to this list
* @throws NullPointerException if the specified collection contains one
* or more null elements and this list does not permit null
* elements, or if the specified collection is null
* @throws IllegalArgumentException if some property of an element of the
* specified collection prevents it from being added to this list
* @throws IndexOutOfBoundsException if the index is out of range
* ({@code index < 0 || index > size()})
*/
未暴露更多源代码,所以这里权且依注释理解功能。
3.结论
-
classpath:/META-INF/resources/",“classpath:/resources/”,“classpath:/static/”,"classpath:/public/"的资源可以直接通过文件名访问
-
ResourceHandlerRegistry由ApplicationContext 和 ServletContext 两个上下文对象配置
-
如有必要,ResourceHandlerRegistry.addResourceLocations可以手动配置包括本地路径在内的资源存放目录
-
- spring.mvc.static-path-pattern:访问地址 spring.web.resources.static-locations:存放路径
例如
spring: mvc: static-path-pattern: /aa/** web: resources: static-locations: classpath:/bb/
则目录bb下的所有文件需要在http://localhost:8888/aa/xxx.js 形式的链接下访问
注意:当配置了这一映射关系之后,默认的资源存储路径将会失效!(参考第一节中this.resourceProperties.isAddMappings())