SpringBoot 源码分析(四) 内置Tomcat分析

这篇具有很好参考价值的文章主要介绍了SpringBoot 源码分析(四) 内置Tomcat分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、Tomcat相关知识

1. tomcat目录结构

Tomcat文件的目录结构
SpringBoot 源码分析(四) 内置Tomcat分析,SSM、SpringBoot源码分析,spring boot,tomcat,firefox

2.启动流程

启动一个Tomcat服务是执行的bin目录下的脚本程序,startup.batstartup.sh.一个是windows的脚本,一个是Linux下的脚本,同样还可以看到两个停止的脚本 shutdown.batshutdown.sh.

SpringBoot 源码分析(四) 内置Tomcat分析,SSM、SpringBoot源码分析,spring boot,tomcat,firefoxstartup.bat脚本内容
SpringBoot 源码分析(四) 内置Tomcat分析,SSM、SpringBoot源码分析,spring boot,tomcat,firefox
catalina.bat脚本文件SpringBoot 源码分析(四) 内置Tomcat分析,SSM、SpringBoot源码分析,spring boot,tomcat,firefox
doStart方法
SpringBoot 源码分析(四) 内置Tomcat分析,SSM、SpringBoot源码分析,spring boot,tomcat,firefox
最后会执行的程序是
SpringBoot 源码分析(四) 内置Tomcat分析,SSM、SpringBoot源码分析,spring boot,tomcat,firefox
SpringBoot 源码分析(四) 内置Tomcat分析,SSM、SpringBoot源码分析,spring boot,tomcat,firefox
MAINCLASS变量是就是Bootstrap.class
SpringBoot 源码分析(四) 内置Tomcat分析,SSM、SpringBoot源码分析,spring boot,tomcat,firefox

3.Bootstrap类

3.1 架构图

Tomcat的架构图如下所示

SpringBoot 源码分析(四) 内置Tomcat分析,SSM、SpringBoot源码分析,spring boot,tomcat,firefox

3.2 流程分析

Bootstrap中的main方法是入口;
SpringBoot 源码分析(四) 内置Tomcat分析,SSM、SpringBoot源码分析,spring boot,tomcat,firefox

bootstrap.init(); // 初始化类加载器
bootstrap.load(); // 间接调用Catalina,创建对象树,然后调用生命周期的init方法初始化整个对象树
bootstrap.start(); // 间接调用Catalina的start方法,然后调用生命周期的start方法启动整个对象树

二、SpringBoot内嵌Tomcat原理

在使用springboot搭建一个web应用程序的时候,我们发现不需要自己搭建一个tomcat服务器,只需要引入spring-boot-starter-web,在应用启动时会自动启动嵌入式的tomcat作为服务器,而tomcat的实现机制也是从自动装配开始的。

1、ServletWebServerFactoryAutoConfiguration

@Configuration(proxyBeanMethods = false)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
		ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
		ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
		ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {

	@Bean
	public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) {
		return new ServletWebServerFactoryCustomizer(serverProperties);
	}

	@Bean
	@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
	public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
			ServerProperties serverProperties) {
		return new TomcatServletWebServerFactoryCustomizer(serverProperties);
	}

	@Bean
	@ConditionalOnMissingFilterBean(ForwardedHeaderFilter.class)
	@ConditionalOnProperty(value = "server.forward-headers-strategy", havingValue = "framework")
	public FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter() {
		ForwardedHeaderFilter filter = new ForwardedHeaderFilter();
		FilterRegistrationBean<ForwardedHeaderFilter> registration = new FilterRegistrationBean<>(filter);
		registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.ERROR);
		registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
		return registration;
	}

	/**
	 * Registers a {@link WebServerFactoryCustomizerBeanPostProcessor}. Registered via
	 * {@link ImportBeanDefinitionRegistrar} for early registration.
	 */
	public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {

		private ConfigurableListableBeanFactory beanFactory;

		@Override
		public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
			if (beanFactory instanceof ConfigurableListableBeanFactory) {
				this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
			}
		}

		@Override
		public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
				BeanDefinitionRegistry registry) {
			if (this.beanFactory == null) {
				return;
			}
			registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",
					WebServerFactoryCustomizerBeanPostProcessor.class);
			registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor",
					ErrorPageRegistrarBeanPostProcessor.class);
		}

		private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name, Class<?> beanClass) {
			if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) {
				RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
				beanDefinition.setSynthetic(true);
				registry.registerBeanDefinition(name, beanDefinition);
			}
		}
	}
}

从这个类上可以看到,当前配置类主要导入了BeanPostProcessorRegister,该类实现了ImportBeanDefinitionRegister接口,可以用来注册额外的BeanDefinition,同时,该类还导入了EmbeddedTomcat,EmbeddedJetty,EmbeddedUndertow三个类,可以根据用户的需求去选择使用哪一个web服务器,默认情况下使用的是tomcat

2、onRefresh()

当自动装配功能完成之后会接着执行onRefresh的方法(ServletWebServerApplicationContext)

@Override
protected void onRefresh() {
    //创建主题对象,不用在意
	super.onRefresh();
	try {
        //开始创建web服务
		createWebServer();
	}
	catch (Throwable ex) {
		throw new ApplicationContextException("Unable to start web server", ex);
	}
}

3、createWebServer()

创建web服务,默认获取的是tomcat的web容器(ServletWebServerApplicationContext)

private void createWebServer() {
	WebServer webServer = this.webServer;
	ServletContext servletContext = getServletContext();
	if (webServer == null && servletContext == null) {
        //获取servletWebServerFactory,从上下文注册bean中可以找到
		ServletWebServerFactory factory = getWebServerFactory();
        //获取servletContextInitializer,获取webServer
		this.webServer = factory.getWebServer(getSelfInitializer());
	}
	else if (servletContext != null) {
		try {
			getSelfInitializer().onStartup(servletContext);
		}
		catch (ServletException ex) {
			throw new ApplicationContextException("Cannot initialize servlet context", ex);
		}
	}
    //替换servlet相关的属性资源
	initPropertySources();
}

如何获取tomcat的bean的实例对象呢?从如下代码中可以看出

ServletWebServerApplicationContext

protected ServletWebServerFactory getWebServerFactory() {
		// Use bean names so that we don't consider the hierarchy
		String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
		if (beanNames.length == 0) {
			throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing "
					+ "ServletWebServerFactory bean.");
		}
		if (beanNames.length > 1) {
			throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple "
					+ "ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));
		}
		return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
	}
protected ServletWebServerFactory getWebServerFactory() {
		// Use bean names so that we don't consider the hierarchy
		String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
		if (beanNames.length == 0) {
			throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing "
					+ "ServletWebServerFactory bean.");
		}
		if (beanNames.length > 1) {
			throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple "
					+ "ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));
		}
		return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
	}

DefaultListableBeanFactoryf

/*
第一个参数type表示要查找的类型
第二个参数表示是否考虑非单例bean
第三个参数表示是否允许提早初始化
*/
@Override
	public String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
        //配置还未被冻结或者类型为null或者不允许早期初始化
		if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
			return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
		}
        //此处注意isConfigurationFrozen为false的时候表示beanDefinition可能还会发生更改和添加,所以不能进行缓存,如果允许非单例bean,那么从保存所有bean的集合中获取,否则从单例bean中获取
		Map<Class<?>, String[]> cache =
				(includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
		String[] resolvedBeanNames = cache.get(type);
		if (resolvedBeanNames != null) {
			return resolvedBeanNames;
		}
        //如果缓存中没有获取到,那么只能重新获取,获取到之后就存入缓存
		resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
		if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
			cache.put(type, resolvedBeanNames);
		}
		return resolvedBeanNames;
	}

private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
		List<String> result = new ArrayList<>();

		// Check all bean definitions.
		for (String beanName : this.beanDefinitionNames) {
			// Only consider bean as eligible if the bean name
			// is not defined as alias for some other bean.
            //如果时别名则跳过(当前集合会保存所有的主beanname,并且不会保存别名,别名由beanfactory中别名map维护)
			if (!isAlias(beanName)) {
				try {
                    //获取合并的beandefinition,合并的beandefinition是指spring整合了父beandefinition的属性,将其beandefinition编程了rootBeanDefinition
					RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
					// Only check bean definition if it is complete.
                    //抽象的beandefinition是不做考虑,抽象的就是拿来继承的,如果允许早期初始化,那么直接短路,进入方法体,如果不允许早期初始化,那么需要进一步判断,如果是不允许早期初始化的,并且beanClass已经被加载或者它是可以早期初始化的,那么如果当前bean是工厂bean,并且指定的bean又是工厂那么这个bean就必须被早期初始化,也就是说就不符合我们制定的allowEagerInit为false的情况,直接跳过

					if (!mbd.isAbstract() && (allowEagerInit ||
							(mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) &&
									!requiresEagerInitForType(mbd.getFactoryBeanName()))) {
                        //如果当前bean是工厂bean
						boolean isFactoryBean = isFactoryBean(beanName, mbd);
                        //如果允许早期初始化,那么基本上会调用最后的isTypeMatch方法,这个方法会导致工厂的实例化,但是当前不允许进行早期实例化在不允许早期实例化的情况下,如果当前bean是工厂bean,那么它只能在已经被创建的情况下调用isTypeMatch进行匹配判断否则只能宣告匹配失败,返回false
						BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
						boolean matchFound = false;
						boolean allowFactoryBeanInit = allowEagerInit || containsSingleton(beanName);
						boolean isNonLazyDecorated = dbd != null && !mbd.isLazyInit();
						if (!isFactoryBean) {
							if (includeNonSingletons || isSingleton(beanName, mbd, dbd)) {
								matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
							}
						}
						else  {
                            //如果没有匹配到并且他是个工厂bean,那么加上&前缀,表示要获取factorybean类型的bean
							if (includeNonSingletons || isNonLazyDecorated ||
									(allowFactoryBeanInit && isSingleton(beanName, mbd, dbd))) {
								matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
							}
							if (!matchFound) {
								// In case of FactoryBean, try to match FactoryBean instance itself next.
								beanName = FACTORY_BEAN_PREFIX + beanName;
								matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
							}
						}
                        //找到便记录到result集合中,等待返回
						if (matchFound) {
							result.add(beanName);
						}
					}
				}
				catch (CannotLoadBeanClassException | BeanDefinitionStoreException ex) {
					if (allowEagerInit) {
						throw ex;
					}
					// Probably a placeholder: let's ignore it for type matching purposes.
					LogMessage message = (ex instanceof CannotLoadBeanClassException) ?
							LogMessage.format("Ignoring bean class loading failure for bean '%s'", beanName) :
							LogMessage.format("Ignoring unresolvable metadata in bean definition '%s'", beanName);
					logger.trace(message, ex);
					onSuppressedException(ex);
				}
			}
		}
// Check manually registered singletons too.
    //从单例注册集合中获取,这个单例集合石保存spring内部注入的单例对象,他们的特点就是没有beanDefinition
		for (String beanName : this.manualSingletonNames) {
			try {
				// In case of FactoryBean, match object created by FactoryBean.
                //如果是工厂bean,那么调用其getObjectType去匹配是否符合指定类型
				if (isFactoryBean(beanName)) {
					if ((includeNonSingletons || isSingleton(beanName)) && isTypeMatch(beanName, type)) {
						result.add(beanName);
						// Match found for this bean: do not match FactoryBean itself anymore.
						continue;
					}
					// In case of FactoryBean, try to match FactoryBean itself next.
					beanName = FACTORY_BEAN_PREFIX + beanName;
				}
				// Match raw bean instance (might be raw FactoryBean).
                //如果没有匹配成功,那么匹配工厂类
				if (isTypeMatch(beanName, type)) {
					result.add(beanName);
				}
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Shouldn't happen - probably a result of circular reference resolution...
				logger.trace(LogMessage.format("Failed to check manually registered singleton with name '%s'", beanName), ex);
			}
		}

		return StringUtils.toStringArray(result);
	}

4、tomcat对象的初始化(ServletWebServerApplicationContext)

private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {
		return this::selfInitialize;
	}

private void selfInitialize(ServletContext servletContext) throws ServletException {
    //使用给定的完全加载的servletContext准备WebApplicationContext
	prepareWebApplicationContext(servletContext);
	registerApplicationScope(servletContext);
    //使用给定的BeanFactory注册特定于web的作用域bean(contextParameters,contextAttributes)
	WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
	for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
		beans.onStartup(servletContext);
	}
}

5、完成内嵌tomcat的api调用(TomcatServletWebServerFactory)

@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
	if (this.disableMBeanRegistry) {
		Registry.disableRegistry();
	}
    //完成tomcat的api调用
	Tomcat tomcat = new Tomcat();
	File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
	tomcat.setBaseDir(baseDir.getAbsolutePath());
	//创建连接器
	Connector connector = new Connector(this.protocol);
	connector.setThrowOnFailure(true);
	//Service相关连接器
	tomcat.getService().addConnector(connector);
	customizeConnector(connector);
	tomcat.setConnector(connector);
	//host相关
	tomcat.getHost().setAutoDeploy(false);
	configureEngine(tomcat.getEngine());
	for (Connector additionalConnector : this.additionalTomcatConnectors) {
		tomcat.getService().addConnector(additionalConnector);
	}
    //准备tomcatEmbeddedContext并设置到tomcat中
	prepareContext(tomcat.getHost(), initializers);
    //构建tomcatWebServer
	return getTomcatWebServer(tomcat);
}

6、getTomcatWebServer()

获取tomcat服务(TomcatServletWebServerFactory)

protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
	return new TomcatWebServer(tomcat, getPort() >= 0);
}
public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
	Assert.notNull(tomcat, "Tomcat Server must not be null");
	this.tomcat = tomcat;
	this.autoStart = autoStart;
    //初始化
	initialize();
}

7、initialize()

完成tomcat的初始化,其中this.tomcat.start();就是会进入到tomcat的逻辑了 这个需要单独看Tomcat的源码了。

private void initialize() throws WebServerException {
		logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));
		synchronized (this.monitor) {
			try {
                //engineName拼接instanceId
				addInstanceIdToEngineName();

				Context context = findContext();
				context.addLifecycleListener((event) -> {
					if (context.equals(event.getSource()) && Lifecycle.START_EVENT.equals(event.getType())) {
						// Remove service connectors so that protocol binding doesn't
						// happen when the service is started.
                        //删除Connectors,以便再启动服务时不发生协议绑定
						removeServiceConnectors();
					}
				});

				// Start the server to trigger initialization listeners
                //启动服务触发初始化监听器
				this.tomcat.start();

				// We can re-throw failure exception directly in the main thread
                //在主线程中重新抛出失败异常
				rethrowDeferredStartupExceptions();

				try {
					ContextBindings.bindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
				}
				catch (NamingException ex) {
					// Naming is not enabled. Continue
				}

				// Unlike Jetty, all Tomcat threads are daemon threads. We create a
				// blocking non-daemon to stop immediate shutdown
                //所有的tomcat线程都是守护线程,我们创建一个阻塞非守护线程来避免立即关闭
				startDaemonAwaitThread();
			}
			catch (Exception ex) {
                //异常停止tomcat
				stopSilently();
				destroySilently();
				throw new WebServerException("Unable to start embedded Tomcat", ex);
			}
		}
	}
-----------------------
    	private void removeServiceConnectors() {
		for (Service service : this.tomcat.getServer().findServices()) {
			Connector[] connectors = service.findConnectors().clone();
            //将将要移除的conntector放到缓存中暂存
			this.serviceConnectors.put(service, connectors);
			for (Connector connector : connectors) {
                //移除connector
				service.removeConnector(connector);
			}
		}
	}

start方法
SpringBoot 源码分析(四) 内置Tomcat分析,SSM、SpringBoot源码分析,spring boot,tomcat,firefox
SpringBoot 源码分析(四) 内置Tomcat分析,SSM、SpringBoot源码分析,spring boot,tomcat,firefox

8、finishRefresh()中tomcat的处理

除了refresh方法之外,在finishRefresh()方法中也对tomcat做了相关的处理(ServletWebServerApplicationContext)

	protected void finishRefresh() {
        //调用父类的finishRefresh方法
		super.finishRefresh();
        //启动webServer
		WebServer webServer = startWebServer();
		if (webServer != null) {
            //发布webServer初始化完成事件
			publishEvent(new ServletWebServerInitializedEvent(webServer, this));
		}
	}
ServletWebServerApplicationContext
	private WebServer startWebServer() {
		WebServer webServer = this.webServer;
		if (webServer != null) {
            //启动webserver
			webServer.start();
		}
		return webServer;
	}

TomcatWebServer

	public void start() throws WebServerException {
		synchronized (this.monitor) {
			if (this.started) {
				return;
			}
			try {
                //添加之前移除的connector
				addPreviouslyRemovedConnectors();
				Connector connector = this.tomcat.getConnector();
				if (connector != null && this.autoStart) {
                    //延迟加载启动
					performDeferredLoadOnStartup();
				}
                //检查connector启动状态是否为失败,失败抛出异常
				checkThatConnectorsHaveStarted();
				this.started = true;
				logger.info("Tomcat started on port(s): " + getPortsDescription(true) + " with context path '"
						+ getContextPath() + "'");
			}
			catch (ConnectorStartFailedException ex) {
                //异常停止tomcat
				stopSilently();
				throw ex;
			}
			catch (Exception ex) {
				if (findBindException(ex) != null) {
					throw new PortInUseException(this.tomcat.getConnector().getPort());
				}
				throw new WebServerException("Unable to start embedded Tomcat server", ex);
			}
			finally {
				Context context = findContext();
                //context解绑classload
				ContextBindings.unbindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
			}
		}
	}
private void addPreviouslyRemovedConnectors() {
		Service[] services = this.tomcat.getServer().findServices();
		for (Service service : services) {
            //从上面移除connector添加的缓存中取出connector
			Connector[] connectors = this.serviceConnectors.get(service);
			if (connectors != null) {
				for (Connector connector : connectors) {
                    //添加到tomcat service中
					service.addConnector(connector);
					if (!this.autoStart) {
                        //如果不是自动启动,则暂停connector
						stopProtocolHandler(connector);
					}
				}
                //添加完成后移除
				this.serviceConnectors.remove(service);
			}
		}
	}
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);
		}
	}
	void deferredLoadOnStartup() throws LifecycleException {
		doWithThreadContextClassLoader(getLoader().getClassLoader(),
				() -> getLoadOnStartupWrappers(findChildren()).forEach(this::load));
	}

9、应用上下文关闭时会调用tomcat的关闭

在refreshContext中注册一个关闭的钩子函数,而钩子函数可以完成关闭的功能

ServletWebServerApplicationContext

	@Override
	protected void onClose() {
		super.onClose();
		stopAndReleaseWebServer();
	}
	private void stopAndReleaseWebServer() {
		WebServer webServer = this.webServer;
		if (webServer != null) {
			try {
				webServer.stop();
				this.webServer = null;
			}
			catch (Exception ex) {
				throw new IllegalStateException(ex);
			}
		}
	}

TomcatWebServer文章来源地址https://www.toymoban.com/news/detail-716050.html

@Override
	public void stop() throws WebServerException {
		synchronized (this.monitor) {
			boolean wasStarted = this.started;
			try {
				this.started = false;
				try {
					stopTomcat();
					this.tomcat.destroy();
				}
				catch (LifecycleException ex) {
					// swallow and continue
				}
			}
			catch (Exception ex) {
				throw new WebServerException("Unable to stop embedded Tomcat", ex);
			}
			finally {
				if (wasStarted) {
					containerCounter.decrementAndGet();
				}
			}
		}
	}

到了这里,关于SpringBoot 源码分析(四) 内置Tomcat分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringBoot配置外部Tomcat项目启动流程源码分析

    SpringBoot应用默认以Jar包方式并且使用内置Servlet容器(默认Tomcat),该种方式虽然简单但是默认不支持JSP并且优化容器比较复杂。故而我们可以使用习惯的外置Tomcat方式并将项目打War包。 ① 同样使用Spring Initializer方式创建项目 ② 打包方式选择\\\"war\\\" ③ 选择添加的模块 ④ 创建的

    2024年02月04日
    浏览(30)
  • SpringBoot源码分析之Tomcat是如何在SpringBoot中启动的?

    一.前言 我们知道SpringBoot可以直接把传统的war包打成可执行的jar包,直接启动。这得益于SpringBoot内置了容器可以直接启动。本文将以 Tomcat 为例,来看看 SpringBoot 是如何启动 Tomcat 的。 一.SpringApplication初始化 调用到最终的run方法我们来看一下 这里面首先创建了一个SpringAppl

    2024年02月05日
    浏览(29)
  • springboot-内置Tomcat

    一、springboot的特性之一 基于springboot的特性  自动装配@Configuretion 注解 二、springboot内置Tomcat步骤 直接看SpringApplication方法的代码块 总纲: 1、在SpringApplication.run 初始化了一个上下文ConfigurableApplicationContext configurableApplicationContext = AnnotationConfigServletWebServerApplicationContext,这里

    2024年02月15日
    浏览(25)
  • SpringBoot源码解读与原理分析(二十七)嵌入式Tomcat

    当Web应用需要部署运行时,传统的做法是将项目打包成war包,然后部署到外置的Web容器中(如最常用的Tomcat容器)。 SpringBoot的一大重要特性是支持嵌入式Web容器,基于SpringBoot的Web应用仅凭一个单独的jar包即可独立运行。 8.1.1 嵌入式Tomcat与普通Tomcat 嵌入式Tomcat是一种可以嵌

    2024年02月22日
    浏览(38)
  • SpringBoot内置Tomcat 配置和切换

    目录 SpringBoot内置Tomcat 配置和切换 基本介绍 内置Tomcat 的配置 application.yml配置 对上面代码解释一下方便理解 通过类来配置Tomcat 注销application.yml 对tomcat 配置,完成测试 切换WebServer, 演示如何切换成Undertow  修改pom.xml , 排除tomcat , 加入Undertow 包的依赖 运行项目,完成测试 S

    2024年02月06日
    浏览(25)
  • SpringBoot---内置Tomcat 配置和切换

    😀前言 本篇博文是关于内置Tomcat 配置和切换,希望你能够喜欢 🏠个人主页:晨犀主页 🧑个人简介:大家好,我是晨犀,希望我的文章可以帮助到大家,您的满意是我的动力😉😉 💕欢迎大家:这里是CSDN,我总结知识的地方,欢迎来到我的博客,感谢大家的观看🥰 如果

    2024年02月12日
    浏览(26)
  • SpringBoot内置tomcat参数调优

    可通过org.springframework.boot.autoconfigure.web.ServerProperties查看,其中包括属性tomcat、jetty、undertow三种服务器的设置,默认启用tomcat。 每一次HTTP请求到达Web服务器,Web服务器都会创建一个线程来处理该请求 min-spare-threads: 最小备用线程数,tomcat启动时的初始化的线程数,默认10。

    2024年02月15日
    浏览(47)
  • SpringBoot 内置 Tomcat 线程数优化配置

    本文解析springboot内置tomcat调优并发线程数的一些参数,并结合源码进行分析。 线程池核心线程数 server.tomcat.min-spare-threads :该参数为tomcat处理业务的核心线程数大小,默认值为10 线程池最大线程数 server.tomcat.max-threads :该参数为tomcat处理业务的最大线程数大小,默认值为2

    2024年02月09日
    浏览(26)
  • Springboot 优化内置服务器Tomcat优化(underTow)

    通过org.springframework.boot.autoconfigure.web.ServerProperties查看,其中包括属性tomcat、jetty、undertow三种服务器的设置,默认启用tomcat。 比较重要的有两个: 初始线程数 和 最大线程数 。 初始线程数: 保障启动的时候,如果有大量用户访问,能够很稳定的接受请求。 最大线程数: 用

    2024年02月04日
    浏览(36)
  • SpringBoot+内置Tomcat配置,参数调优,最大并发量,最大连接数

    SpringBoot开发最大的好处是简化配置,内置了Tomcat, 在SpringBoot2.0.x版本中内置Tomcat版本是8.5.x,SpringBoot内置Tomcat的默认设置中,Tomcat的等待队列长度默认是100,Tomcat的最小工作线程数默认分配10,Tomcat的最大线程数是200,最大连接数是10000,至于最大并发量和最大连接数,常常理

    2024年02月09日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包