如何在 Springboot 2.3.12 中将 Tomcat APR 协议连接器与嵌入式 Tomcat 9 集成?

问题描述 投票:0回答:2

我需要使用APR协议连接器替换Springboot 2.3.12的嵌入式Tomcat 9中默认的NIO协议连接器,请问如何实现?

java spring-boot nio apr embedded-tomcat
2个回答
0
投票
@Component
public class TomcatWebServerFactoryCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {

    @Override
    public void customize(TomcatServletWebServerFactory factory) {
        factory.setProtocol("org.apache.coyote.http11.Http11AprProtocol");
    }
}

0
投票

解决方案基于:https://dirask.com/posts/Spring-Boot-2-example-APR-native-library-configuration-with-Tomcat-9-Http11AprProtocol-pq6xxj

首先,你应该安装APR原生库:

apt-get install libapr1-dev libssl-dev

稍后,添加到您的项目

TomcatAprConfig.java
文件:

package com.example.config;

import org.apache.catalina.LifecycleListener;
import org.apache.catalina.core.AprLifecycleListener;
import org.apache.coyote.http11.Http11AprProtocol;
import org.apache.coyote.http2.Http2Protocol;
import org.apache.tomcat.util.buf.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.Ssl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

@Configuration
public class TomcatAprConfig {

    // properties

    private String publicCertificatePath = "/path/to/certificates/public_certificate.pem";
    private String privateKeyPath = "/path/to/certificates/private_key.pem";

    private int compressionMinSize = 2048;
    private String compressionMimeTypes = "text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json,application/xml";

    // public methods

    @Bean(name = "tomcatServletWebServerFactory")
    public TomcatServletWebServerFactory createServerFactory(ServerProperties serverProperties, ResourceLoader resourceLoader) {
        TomcatServletWebServerFactory serverFactory = new TomcatServletWebServerFactory() {
            @Override
            public Ssl getSsl() {
                return null;  // null returned to stop the default SSL customizer
            }
        };
        serverFactory.setProtocol("org.apache.coyote.http11.Http11AprProtocol");  // the protocol that will enable APR
        serverFactory.setContextLifecycleListeners(this.createLifecycleListeners());
        serverFactory.setTomcatConnectorCustomizers(this.createConnectorCustomizers(serverProperties, resourceLoader));
        return serverFactory;
    }

    // private methods

    private List<AprLifecycleListener> createLifecycleListeners() {
        AprLifecycleListener lifecycleListener = new AprLifecycleListener();
        return Collections.singletonList(lifecycleListener);
    }

    private List<TomcatConnectorCustomizer> createConnectorCustomizers(ServerProperties serverProperties, ResourceLoader resourceLoader) {
        TomcatConnectorCustomizer connectorCustomizer = tomcatConnector -> {
            Http11AprProtocol aprProtocol = (Http11AprProtocol) tomcatConnector.getProtocolHandler();
                if (this.publicCertificatePath == null) {
                    throw new RuntimeException("Public certificate path is not configured.");
                }
                if (this.privateKeyPath == null) {
                    throw new RuntimeException("Private key  path is not configured.");
                }
                Ssl connectionSsl = serverProperties.getSsl();
                String[] connectionCiphers = connectionSsl.getCiphers();
                String[] connectionProtocols = connectionSsl.getEnabledProtocols();
                tomcatConnector.setSecure(true);
                tomcatConnector.setScheme("https");
                aprProtocol.setSSLEnabled(true);
                if (connectionProtocols != null && connectionProtocols.length > 0) {
                    aprProtocol.setSslEnabledProtocols(this.joinStrings(connectionProtocols));
                }
                if (connectionCiphers != null && connectionCiphers.length > 0) {
                    aprProtocol.setCiphers(this.joinStrings(connectionCiphers));
                }
                try {
                    aprProtocol.setSSLCertificateFile(this.resolvePath(resourceLoader, this.publicCertificatePath));
                    aprProtocol.setSSLCertificateKeyFile(this.resolvePath(resourceLoader, this.privateKeyPath));
                } catch (Exception ex) {
                    throw new RuntimeException(ex);
                }
                Http2Protocol http2Protocol = new Http2Protocol();
                http2Protocol.setCompression("on");
                http2Protocol.setCompressibleMimeType(this.compressionMimeTypes);
                http2Protocol.setCompressionMinSize(this.compressionMinSize);
                tomcatConnector.addUpgradeProtocol(http2Protocol);
        };
        return Collections.singletonList(connectorCustomizer);
    }

    private String joinStrings(String[] strings) {
        List<String> list = Arrays.asList(strings);
        return StringUtils.join(list, ',');
    }

    private String resolvePath(ResourceLoader loader, String path) throws IOException {
        Resource resource = loader.getResource(path);
        try {
            File file = resource.getFile();
            return file.getAbsolutePath();
        } catch (Exception ex) {
            throw new IOException("Absolute '" + path + "' path resolving error.", ex);
        }
    }
}

最后,运行应用程序使用:

java -Djava.library.path="/usr/lib/x86_64-linux-gnu" -jar my-application.jar
© www.soinside.com 2019 - 2024. All rights reserved.