spring.mvc.servlet.load-on-startup属性方法源码解读
作者:codecraft
这篇文章主要介绍了spring.mvc.servlet.load-on-startup的属性方法源码解读,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
序
本文主要研究一下spring.mvc.servlet.load-on-startup
spring.mvc.servlet.load-on-startup
org/springframework/boot/autoconfigure/web/servlet/WebMvcProperties.java
@ConfigurationProperties(prefix = "spring.mvc") public class WebMvcProperties { //...... private final Servlet servlet = new Servlet(); public static class Servlet { /** * Path of the dispatcher servlet. */ private String path = "/"; /** * Load on startup priority of the dispatcher servlet. */ private int loadOnStartup = -1; public String getPath() { return this.path; } public void setPath(String path) { Assert.notNull(path, "Path must not be null"); Assert.isTrue(!path.contains("*"), "Path must not contain wildcards"); this.path = path; } public int getLoadOnStartup() { return this.loadOnStartup; } public void setLoadOnStartup(int loadOnStartup) { this.loadOnStartup = loadOnStartup; } public String getServletMapping() { if (this.path.equals("") || this.path.equals("/")) { return "/"; } if (this.path.endsWith("/")) { return this.path + "*"; } return this.path + "/*"; } public String getPath(String path) { String prefix = getServletPrefix(); if (!path.startsWith("/")) { path = "/" + path; } return prefix + path; } public String getServletPrefix() { String result = this.path; int index = result.indexOf('*'); if (index != -1) { result = result.substring(0, index); } if (result.endsWith("/")) { result = result.substring(0, result.length() - 1); } return result; } } }
WebMvcProperties.Servlet定义了loadOnStartup属性,默认为-1
DispatcherServletAutoConfiguration
org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfiguration.java
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnClass(DispatcherServlet.class) @AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class) public class DispatcherServletAutoConfiguration { //...... @Configuration(proxyBeanMethods = false) @Conditional(DispatcherServletRegistrationCondition.class) @ConditionalOnClass(ServletRegistration.class) @EnableConfigurationProperties(WebMvcProperties.class) @Import(DispatcherServletConfiguration.class) protected static class DispatcherServletRegistrationConfiguration { @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME) @ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet, WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) { DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet, webMvcProperties.getServlet().getPath()); registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME); registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup()); multipartConfig.ifAvailable(registration::setMultipartConfig); return registration; } } //...... }
DispatcherServletRegistrationConfiguration注册了DispatcherServletRegistrationBean,它会读取webMvcProperties.getServlet().getLoadOnStartup()然后设置其loadOnStartup属性
ServletRegistrationBean
org/springframework/boot/web/servlet/ServletRegistrationBean.java
public class ServletRegistrationBean<T extends Servlet> extends DynamicRegistrationBean<ServletRegistration.Dynamic> { private static final String[] DEFAULT_MAPPINGS = { "/*" }; private T servlet; private Set<String> urlMappings = new LinkedHashSet<>(); private boolean alwaysMapUrl = true; private int loadOnStartup = -1; private MultipartConfigElement multipartConfig; //...... @Override protected void configure(ServletRegistration.Dynamic registration) { super.configure(registration); String[] urlMapping = StringUtils.toStringArray(this.urlMappings); if (urlMapping.length == 0 && this.alwaysMapUrl) { urlMapping = DEFAULT_MAPPINGS; } if (!ObjectUtils.isEmpty(urlMapping)) { registration.addMapping(urlMapping); } registration.setLoadOnStartup(this.loadOnStartup); if (this.multipartConfig != null) { registration.setMultipartConfig(this.multipartConfig); } } }
ServletRegistrationBean定义了loadOnStartup属性,默认为-1,其configure方法会设置loadOnStartup到ServletRegistration.Dynamic
StandardWrapper
org/apache/catalina/core/StandardWrapper.java
/** * Set the load-on-startup order value (negative value means * load on first call). * * @param value New load-on-startup value */ @Override public void setLoadOnStartup(int value) { int oldLoadOnStartup = this.loadOnStartup; this.loadOnStartup = value; support.firePropertyChange("loadOnStartup", Integer.valueOf(oldLoadOnStartup), Integer.valueOf(this.loadOnStartup)); } /** * @return the load-on-startup order value (negative value means * load on first call). */ @Override public int getLoadOnStartup() { if (isJspServlet && loadOnStartup < 0) { /* * JspServlet must always be preloaded, because its instance is * used during registerJMX (when registering the JSP * monitoring mbean) */ return Integer.MAX_VALUE; } else { return this.loadOnStartup; } }
loadOnStartup属性最后设置到了tomcat的StandardWrapper
StandardContext
org/apache/catalina/core/StandardContext.java
/** * Load and initialize all servlets marked "load on startup" in the * web application deployment descriptor. * * @param children Array of wrappers for all currently defined * servlets (including those not declared load on startup) * @return <code>true</code> if load on startup was considered successful */ public boolean loadOnStartup(Container children[]) { // Collect "load on startup" servlets that need to be initialized TreeMap<Integer, ArrayList<Wrapper>> map = new TreeMap<>(); for (Container child : children) { Wrapper wrapper = (Wrapper) child; int loadOnStartup = wrapper.getLoadOnStartup(); if (loadOnStartup < 0) { continue; } Integer key = Integer.valueOf(loadOnStartup); ArrayList<Wrapper> list = map.get(key); if (list == null) { list = new ArrayList<>(); map.put(key, list); } list.add(wrapper); } // Load the collected "load on startup" servlets for (ArrayList<Wrapper> list : map.values()) { for (Wrapper wrapper : list) { try { wrapper.load(); } catch (ServletException e) { getLogger().error(sm.getString("standardContext.loadOnStartup.loadException", getName(), wrapper.getName()), StandardWrapper.getRootCause(e)); // NOTE: load errors (including a servlet that throws // UnavailableException from the init() method) are NOT // fatal to application startup // unless failCtxIfServletStartFails="true" is specified if(getComputedFailCtxIfServletStartFails()) { return false; } } } } return true; }
StandardContext的loadOnStartup方法会取出所有loadOnStartup大于等于0的wrapper,按loadOnStartup值放入到TreeMap<Integer, ArrayList<Wrapper>>,然后遍历该TreeMap挨个执行wrapper.load()进行加载
小结
springboot的spring.mvc.servlet.load-on-startup属性,最后设置到tomcat的StandardWrapper;而tomcat的StandardContext的loadOnStartup方法会取出所有loadOnStartup大于等于0的wrapper,按loadOnStartup值放入到TreeMap<Integer, ArrayList<Wrapper>>
,然后遍历该TreeMap挨个执行wrapper.load()进行加载。
以上就是聊聊spring.mvc.servlet.load-on-startup的详细内容,更多关于spring.mvc.servlet.load-on-startup的资料请关注脚本之家其它相关文章!