我需要使用APR协议连接器替换Springboot 2.3.12的嵌入式Tomcat 9中默认的NIO协议连接器,请问如何实现?
@Component
public class TomcatWebServerFactoryCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
@Override
public void customize(TomcatServletWebServerFactory factory) {
factory.setProtocol("org.apache.coyote.http11.Http11AprProtocol");
}
}
首先,你应该安装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