Spring Boot 3.2.0 Tomcat虚拟线程初体验 (部分装配解析)
作者:mmseoamin日期:2023-12-18

写在前面

  • spring boot 3 已经提供了对虚拟线程的支持。

  • 虚拟线程和平台线程主要区别在于,虚拟线程在运行周期内不依赖操作系统线程:它们与硬件脱钩,因此被称为 “虚拟”。这种解耦是由 JVM 提供的抽象层赋予的。

  • 虚拟线程的运行成本远低于平台线程。消耗的内存要少得多。这就是为什么可以创建数百万个虚拟线程而不会出现内存不足的问题,而标准平台(或内核)线程只能创建数百个。

  • 虚拟线程会优先使用JVM提供,如果不能使用JVM提供,则考虑使用由平台线程支持的“虚拟线程” ,相关源代码参考java.lang.ThreadBuilders#newVirtualThread

    版本要求

    • spring boot 3.2.0
    • jdk 21

      pom.xml

      
      
          4.0.0
          
              org.springframework.boot
              spring-boot-starter-parent
              3.2.0
               
          
          net.jlxxw
          boot3-demo
          1.0.0.20231128
          boot3-demo
          boot3-demo
          
              21
              UTF-8
              UTF-8
              3.2.0
          
          
             
              
                  org.apache.httpcomponents.client5
                  httpclient5-fluent
              
              
                  org.springframework.boot
                  spring-boot-starter-aop
              
              
                  org.springframework.boot
                  spring-boot-configuration-processor
              
          
              
                  org.springframework.boot
                  spring-boot-starter-logging
              
              
                  org.springframework.boot
                  spring-boot-starter-web
              
              
                  org.springframework.boot
                  spring-boot-starter-test
                  test
              
         
          
          
              
                  
                      org.graalvm.buildtools
                      native-maven-plugin
                      
                          
                          ${project.artifactId}
                          
                          
                          
                          
                      
      
      
      
      
      
      
      
      
      
                  
                  
                      org.springframework.boot
                      spring-boot-maven-plugin
                  
              
          
      
      

      yml

      spring:
        #启动虚拟线程的必须配置
        threads:
          virtual:
            # 启用虚拟线程技术,增加系统并发能力
            enabled: true
      

      自动装配解析

      Tomcat 虚拟线程自动配置类

      org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration.TomcatWebServerFactoryCustomizerConfiguration#tomcatVirtualThreadsProtocolHandlerCustomizer

      /*
       * Copyright 2012-2023 the original author or authors.
       *
       * Licensed under the Apache License, Version 2.0 (the "License");
       * you may not use this file except in compliance with the License.
       * You may obtain a copy of the License at
       *
       *      https://www.apache.org/licenses/LICENSE-2.0
       *
       * Unless required by applicable law or agreed to in writing, software
       * distributed under the License is distributed on an "AS IS" BASIS,
       * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       * See the License for the specific language governing permissions and
       * limitations under the License.
       */
      package org.springframework.boot.autoconfigure.web.embedded;
      import io.undertow.Undertow;
      import org.apache.catalina.startup.Tomcat;
      import org.apache.coyote.UpgradeProtocol;
      import org.eclipse.jetty.ee10.webapp.WebAppContext;
      import org.eclipse.jetty.server.Server;
      import org.eclipse.jetty.util.Loader;
      import org.xnio.SslClientAuthMode;
      import reactor.netty.http.server.HttpServer;
      import org.springframework.boot.autoconfigure.AutoConfiguration;
      import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
      import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
      import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWarDeployment;
      import org.springframework.boot.autoconfigure.condition.ConditionalOnThreading;
      import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
      import org.springframework.boot.autoconfigure.thread.Threading;
      import org.springframework.boot.autoconfigure.web.ServerProperties;
      import org.springframework.boot.context.properties.EnableConfigurationProperties;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.core.env.Environment;
      /**
       * {@link EnableAutoConfiguration Auto-configuration} for embedded servlet and reactive
       * web servers customizations.
       *
       * @author Phillip Webb
       * @since 2.0.0
       */
      @AutoConfiguration
      @ConditionalOnNotWarDeployment
      @ConditionalOnWebApplication
      @EnableConfigurationProperties(ServerProperties.class)
      public class EmbeddedWebServerFactoryCustomizerAutoConfiguration {
      	/**
      	 * Nested configuration if Tomcat is being used.
      	 */
      	@Configuration(proxyBeanMethods = false)
      	@ConditionalOnClass({ Tomcat.class, UpgradeProtocol.class })
      	public static class TomcatWebServerFactoryCustomizerConfiguration {
      		@Bean
      		public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(Environment environment,
      				ServerProperties serverProperties) {
      			return new TomcatWebServerFactoryCustomizer(environment, serverProperties);
      		}
      		@Bean
      		@ConditionalOnThreading(Threading.VIRTUAL)
      		TomcatVirtualThreadsWebServerFactoryCustomizer tomcatVirtualThreadsProtocolHandlerCustomizer() {
      			return new TomcatVirtualThreadsWebServerFactoryCustomizer();
      		}
      	}
      	/**
      	 * Nested configuration if Jetty is being used.
      	 */
      	@Configuration(proxyBeanMethods = false)
      	@ConditionalOnClass({ Server.class, Loader.class, WebAppContext.class })
      	public static class JettyWebServerFactoryCustomizerConfiguration {
      		@Bean
      		public JettyWebServerFactoryCustomizer jettyWebServerFactoryCustomizer(Environment environment,
      				ServerProperties serverProperties) {
      			return new JettyWebServerFactoryCustomizer(environment, serverProperties);
      		}
      		@Bean
      		@ConditionalOnThreading(Threading.VIRTUAL)
      		JettyVirtualThreadsWebServerFactoryCustomizer jettyVirtualThreadsWebServerFactoryCustomizer(
      				ServerProperties serverProperties) {
      			return new JettyVirtualThreadsWebServerFactoryCustomizer(serverProperties);
      		}
      	}
      	/**
      	 * Nested configuration if Undertow is being used.
      	 */
      	@Configuration(proxyBeanMethods = false)
      	@ConditionalOnClass({ Undertow.class, SslClientAuthMode.class })
      	public static class UndertowWebServerFactoryCustomizerConfiguration {
      		@Bean
      		public UndertowWebServerFactoryCustomizer undertowWebServerFactoryCustomizer(Environment environment,
      				ServerProperties serverProperties) {
      			return new UndertowWebServerFactoryCustomizer(environment, serverProperties);
      		}
      	}
      	/**
      	 * Nested configuration if Netty is being used.
      	 */
      	@Configuration(proxyBeanMethods = false)
      	@ConditionalOnClass(HttpServer.class)
      	public static class NettyWebServerFactoryCustomizerConfiguration {
      		@Bean
      		public NettyWebServerFactoryCustomizer nettyWebServerFactoryCustomizer(Environment environment,
      				ServerProperties serverProperties) {
      			return new NettyWebServerFactoryCustomizer(environment, serverProperties);
      		}
      	}
      }
      

      Spring Boot 3.2.0 Tomcat虚拟线程初体验 (部分装配解析),在这里插入图片描述,第1张

      Tomcat虚拟线程定制器

      org.springframework.boot.autoconfigure.web.embedded.TomcatVirtualThreadsWebServerFactoryCustomizer

      /*
       * Copyright 2012-2023 the original author or authors.
       *
       * Licensed under the Apache License, Version 2.0 (the "License");
       * you may not use this file except in compliance with the License.
       * You may obtain a copy of the License at
       *
       *      https://www.apache.org/licenses/LICENSE-2.0
       *
       * Unless required by applicable law or agreed to in writing, software
       * distributed under the License is distributed on an "AS IS" BASIS,
       * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       * See the License for the specific language governing permissions and
       * limitations under the License.
       */
      package org.springframework.boot.autoconfigure.web.embedded;
      import org.apache.coyote.ProtocolHandler;
      import org.apache.tomcat.util.threads.VirtualThreadExecutor;
      import org.springframework.boot.web.embedded.tomcat.ConfigurableTomcatWebServerFactory;
      import org.springframework.boot.web.server.WebServerFactoryCustomizer;
      import org.springframework.core.Ordered;
      /**
       * Activates {@link VirtualThreadExecutor} on {@link ProtocolHandler Tomcat's protocol
       * handler}.
       *
       * @author Moritz Halbritter
       * @since 3.2.0
       */
      public class TomcatVirtualThreadsWebServerFactoryCustomizer
      		implements WebServerFactoryCustomizer, Ordered {
      	@Override
      	public void customize(ConfigurableTomcatWebServerFactory factory) {
      		factory.addProtocolHandlerCustomizers(
      				(protocolHandler) -> protocolHandler.setExecutor(new VirtualThreadExecutor("tomcat-handler-")));
      	}
      	@Override
      	public int getOrder() {
      		return TomcatWebServerFactoryCustomizer.ORDER + 1;
      	}
      }
      

      新的虚拟线程池

      org.apache.tomcat.util.threads.VirtualThreadExecutor

      /*
       *  Licensed to the Apache Software Foundation (ASF) under one or more
       *  contributor license agreements.  See the NOTICE file distributed with
       *  this work for additional information regarding copyright ownership.
       *  The ASF licenses this file to You under the Apache License, Version 2.0
       *  (the "License"); you may not use this file except in compliance with
       *  the License.  You may obtain a copy of the License at
       *
       *      http://www.apache.org/licenses/LICENSE-2.0
       *
       *  Unless required by applicable law or agreed to in writing, software
       *  distributed under the License is distributed on an "AS IS" BASIS,
       *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       *  See the License for the specific language governing permissions and
       *  limitations under the License.
       */
      package org.apache.tomcat.util.threads;
      import java.util.concurrent.Executor;
      import org.apache.tomcat.util.compat.JreCompat;
      /**
       * An executor that uses a new virtual thread for each task.
       */
      public class VirtualThreadExecutor implements Executor {
          private final JreCompat jreCompat = JreCompat.getInstance();
          private Object threadBuilder;
          public VirtualThreadExecutor(String namePrefix) {
              threadBuilder = jreCompat.createVirtualThreadBuilder(namePrefix);
          }
          @Override
          public void execute(Runnable command) {
              jreCompat.threadBuilderStart(threadBuilder, command);
          }
      }
      

      测试对比效果

      启用虚拟线程

      Spring Boot 3.2.0 Tomcat虚拟线程初体验 (部分装配解析),在这里插入图片描述,第2张

      未启用虚拟线程

      Spring Boot 3.2.0 Tomcat虚拟线程初体验 (部分装配解析),在这里插入图片描述,第3张