在 Spring Boot 中的多个连接器之间共享嵌入式 Tomcat 执行器

Posted

技术标签:

【中文标题】在 Spring Boot 中的多个连接器之间共享嵌入式 Tomcat 执行器【英文标题】:Share embedded Tomcat executor between multiple connectors in Spring Boot 【发布时间】:2018-06-25 11:25:00 【问题描述】:

我正在尝试使用带有两个连接器(一个 HTTP 和一个 HTTPS)和一个共享执行器的 Spring Boot 设置一个嵌入式 Tomcat。

我已经在 Spring Boot application.properties 上配置了 HTTPS 连接器,然后按照documentation 中的描述以编程方式添加了 HTTP 连接器。

但是,我没有看到任何选项可以为两个连接器使用相同的 Executor。我想将这种设置翻译成 Spring Boot 的配置:

<Executor name="tomcatSharedThreadPool" namePrefix="catalina-exec-" 
    maxThreads="150" minSpareThreads="4"/>

<Connector executor="tomcatSharedThreadPool"
           port="80" protocol="HTTP/1.1" 
           connectionTimeout="20000" 
           redirectPort="443" />
<Connector executor="tomcatSharedThreadPool"
           port="443" protocol="HTTP/1.1" 
           connectionTimeout="20000" />

有人知道怎么做吗?

谢谢。

【问题讨论】:

尽管这个问题比较老,但有一个重复的标题更好=更容易找到... Configure Spring Boot with two ports的可能重复 【参考方案1】:

考虑一下我博客文章中的这个改编的 sn-p:Configuring Tomcat to Listen on Multiple ports using Spring Boot

@Configuration
public class EmbeddedTomcatConfiguration 

    @Value("$server.port")
    private String serverPort;

    @Value("$management.port:$server.port")
    private String managementPort;

    @Value("$server.additionalPorts:null")
    private String additionalPorts;

    @Bean
    public EmbeddedServletContainerFactory servletContainer() 
        TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
        Connector[] additionalConnectors = this.additionalConnector();
        if (additionalConnectors != null && additionalConnectors.length > 0) 
            tomcat.addAdditionalTomcatConnectors(additionalConnectors);
        
        return tomcat;
    

    private Connector[] additionalConnector() 
        if (StringUtils.isBlank(this.additionalPorts)) 
            return null;
        
        Set<String> defaultPorts = Sets.newHashSet(this.serverPort, this.managementPort);
        String[] ports = this.additionalPorts.split(",");
        List<Connector> result = new ArrayList<>();
        for (String port : ports) 
            if (!defaultPorts.contains(port)) 
                Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
                connector.setScheme("http");
                connector.setPort(Integer.valueOf(port));
                result.add(connector);
            
        
        return result.toArray(new Connector[] );
    

到目前为止还没有设置执行器,请随意测试在tomcat.addAdditionalTomcatConnectors(additionalConnectors);之后添加这些行:

tomcat.addConnectorCustomizers(new TomcatConnectorCustomizer() 

                @Override
                public void customize(Connector connector) 
                    ProtocolHandler handler = connector.getProtocolHandler();
                    if (handler instanceof AbstractProtocol) 
                        AbstractProtocol<?> protocol = (AbstractProtocol<?>) handler;
                        protocol.setExecutor(<your executor bean>);
                    
                
            );

【讨论】:

感谢您的帮助,我刚刚完成了您的回答。 如果您认为我的回答可以帮助您回答您的问题,您会考虑将其标记为“答案”吗?谢谢【参考方案2】:

为了让 Tomcat 管理 executor,您必须将自定义的 executor 添加到 Tomcat 服务中,以便将其集成到 Tomcat 生命周期中。

为此,请使用TomcatEmbeddedServletContainerFactory 的方法addConnectorCustomizers。然后,在连接器定制器中,您可以访问 Tomcat 服务,以便将您的自定义执行器添加到 Tomcat 生命周期并设置到每个连接器。

public class MultipleConnectorCustomizer implements TomcatConnectorCustomizer 
@Override
public void customize(final Connector pConnector) 
    // Create shared Tomcat executor
    Service tomcatService = pConnector.getService();
    StandardThreadExecutor executor = createExecutor();
    tomcatService.addExecutor(executor);

    // Customize default connector (HTTPS created by the TomcatEmbeddedServletContainerFactory)
    ProtocolHandler handler = pConnector.getProtocolHandler();
    if (handler instanceof AbstractProtocol) 
        AbstractProtocol<?> protocol = (AbstractProtocol<?>) handler;
        protocol.setExecutor(executor);
    

    // Create additional redirected HTTP connector
    Connector additionalConnector = new Connector(fTomcatProperties.getProtocol().getProtocol());
    additionalConnector.setPort(fTomcatProperties.getHttpRedirectedPort().intValue());
    additionalConnector.setRedirectPort(fServerProperties.getPort().intValue());
    ProtocolHandler additionalHandler = additionalConnector.getProtocolHandler();
    if (additionalHandler instanceof AbstractProtocol) 
        AbstractProtocol<?> protocol = (AbstractProtocol<?>) additionalHandler;
        protocol.setExecutor(executor);
    

    tomcatService.addConnector(additionalConnector);

【讨论】:

以上是关于在 Spring Boot 中的多个连接器之间共享嵌入式 Tomcat 执行器的主要内容,如果未能解决你的问题,请参考以下文章

最佳实践——在应用之间共享 Spring-boot Service 和 Repo 层代码

一些 Spring Boot 服务之间的共享配置

SPring Boot Services 之间的共享配置(在 git 上)

使用spring-boot在多个数据库之间进行数据迁移

如何跨多个 Spring Boot 应用程序共享 H2 内存数据库?

在 Spring Boot 中的多个包上使用 @ComponentScan 时出错