当前位置: 首页 > news >正文

聊聊spring.mvc.servlet.load-on-startup

本文主要研究一下

WebMvcProperties$Servlet

org/springframework/boot/autoconfigure/web/servlet/WebMvcProperties.java

	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;}}

loadOnStartup默认为-1

DispatcherServletAutoConfiguration

org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfiguration.java

	@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;}}

这里注册了dispatcherServlet,并设置loadOnStartup

ServletRegistrationBean

org/springframework/boot/web/servlet/ServletRegistrationBean.java

	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);}}

configure最后设置到ServletRegistration.Dynamic

ApplicationServletRegistration

org/apache/catalina/core/ApplicationServletRegistration.java

    public void setLoadOnStartup(int loadOnStartup) {wrapper.setLoadOnStartup(loadOnStartup);}

最后是设置到tomcat的Wrapper.loadOnStartup

TomcatWebServer

org/springframework/boot/web/embedded/tomcat/TomcatWebServer.java

	public void start() throws WebServerException {synchronized (this.monitor) {if (this.started) {return;}try {addPreviouslyRemovedConnectors();Connector connector = this.tomcat.getConnector();if (connector != null && this.autoStart) {performDeferredLoadOnStartup();}checkThatConnectorsHaveStarted();this.started = true;logger.info("Tomcat started on port(s): " + getPortsDescription(true) + " with context path '"+ getContextPath() + "'");}catch (ConnectorStartFailedException ex) {stopSilently();throw ex;}catch (Exception ex) {PortInUseException.throwIfPortBindingException(ex, () -> this.tomcat.getConnector().getPort());throw new WebServerException("Unable to start embedded Tomcat server", ex);}finally {Context context = findContext();ContextBindings.unbindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());}}}

TomcatWebServer的start方法对于autoStart为true(默认)的会执行performDeferredLoadOnStartup

performDeferredLoadOnStartup

org/springframework/boot/web/embedded/tomcat/TomcatWebServer.java

	private void performDeferredLoadOnStartup() {try {for (Container child : this.tomcat.getHost().findChildren()) {if (child instanceof TomcatEmbeddedContext) {((TomcatEmbeddedContext) child).deferredLoadOnStartup();}}}catch (Exception ex) {if (ex instanceof WebServerException) {throw (WebServerException) ex;}throw new WebServerException("Unable to start embedded Tomcat connectors", ex);}}

performDeferredLoadOnStartup遍历child挨个执行deferredLoadOnStartup

deferredLoadOnStartup

org/springframework/boot/web/embedded/tomcat/TomcatEmbeddedContext.java

	void deferredLoadOnStartup() throws LifecycleException {doWithThreadContextClassLoader(getLoader().getClassLoader(),() -> getLoadOnStartupWrappers(findChildren()).forEach(this::load));}private Stream<Wrapper> getLoadOnStartupWrappers(Container[] children) {Map<Integer, List<Wrapper>> grouped = new TreeMap<>();for (Container child : children) {Wrapper wrapper = (Wrapper) child;int order = wrapper.getLoadOnStartup();if (order >= 0) {grouped.computeIfAbsent(order, (o) -> new ArrayList<>()).add(wrapper);}}return grouped.values().stream().flatMap(List::stream);}	

它通过getLoadOnStartupWrappers获取Wrapper,然后挨个执行其load方法

load

org/springframework/boot/web/embedded/tomcat/TomcatEmbeddedContext.java

	private void load(Wrapper wrapper) {try {wrapper.load();}catch (ServletException ex) {String message = sm.getString("standardContext.loadOnStartup.loadException", getName(), wrapper.getName());if (getComputedFailCtxIfServletStartFails()) {throw new WebServerException(message, ex);}getLogger().error(message, StandardWrapper.getRootCause(ex));}}

load方法即执行wrapper.load()

load

org/apache/catalina/core/StandardWrapper.java

    public synchronized void load() throws ServletException {instance = loadServlet();if (!instanceInitialized) {initServlet(instance);}if (isJspServlet) {StringBuilder oname = new StringBuilder(getDomain());oname.append(":type=JspMonitor");oname.append(getWebModuleKeyProperties());oname.append(",name=");oname.append(getName());oname.append(getJ2EEKeyProperties());try {jspMonitorON = new ObjectName(oname.toString());Registry.getRegistry(null, null).registerComponent(instance, jspMonitorON, null);} catch (Exception ex) {log.warn(sm.getString("standardWrapper.jspMonitorError", instance));}}}

tomcat的StandardWrapper的load是个同步方法,它加载和初始化servlet,如果已经加载或初始化不会重复加载

小结

springboot提供了spring.mvc.servlet.load-on-startup配置,可以设置未非负,这样子springboot启动时可以对servlet进行加载与初始化。

http://www.lqws.cn/news/456679.html

相关文章:

  • 浏览器调试核心技术指南:从基础到高级的完全掌握
  • el-table复杂表头(多级表头行或列的合并)
  • Llama 4 模型卡及提示格式介绍
  • 数据融合平台是什么?如何搭建数据融合平台?
  • windows清理系统备份文件夹WinSxS文件夹清理
  • 深入理解JVM执行引擎
  • FramePack 安装指南(中文)
  • 层级冲突的处理,弹窗生成遮罩问题
  • Xinference部署教程
  • 【CS创世SD NAND征文】STM32户外无线终端管理设备的数据存储方案
  • SelectDB 在 AWS Graviton ARM 架构下相比 x86 实现 36% 性价比提升
  • 代码随想录day10栈和队列1
  • Java 通过QQ邮箱发送邮件(包括附件) 直接可以使用
  • Postman接口测试完整版
  • Docker 容器技术入门与环境部署
  • 运算放大器
  • 应用层协议HTTP
  • shell脚本--变量
  • GNU Octave 基础教程(2):第一个 Octave 程序
  • 碳中和时代的家电革命,从华为智选IAM看科技企业的环保担当
  • conda导出环境文件requirements.txt
  • 解决 Conda 玑境激活问题:缺少 `bin/activate` 文件的应对方法
  • react 面试题
  • 信创 CDC 实战|国产数据库的数据高速通道:OceanBase 实时入仓 StarRocks
  • flask静态资源与模板页面、模板用户登录案例
  • 服务网格安全(Istio):用零信任架构重构微服务通信安全
  • 【系统规划与管理师第二版】1.3 新一代信息技术及发展
  • 三维视频融合怎么弄?三步实现精准投射与自由修剪
  • 如何在服务器终端下载百度网盘数据
  • Spring 的IoC 和 AOP