Springboot静态资源加载的简单探究

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())

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值