はじめに
Apache httpdとSpring Boot (Tomcat)連携のための設定、必要なクラスなどのメモ。
バージョン
Apache httpd 2.4.39
$ /usr/local/bin/apachectl -v
Server version: Apache/2.4.39 (Unix)
Server built: Apr 19 2019 17:53:55
Spring Boot v2.1.6.RELEASE
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.6.RELEASE)
AjpによるApache httpdとTomcatの連携
httpd.conf
LoadModule proxy_module lib/httpd/modules/mod_proxy.so
LoadModule proxy_ajp_module lib/httpd/modules/mod_proxy_ajp.so
<IfModule proxy_ajp_module>
Include /usr/local/etc/httpd/extra/httpd-proxy.conf
</IfModule>
LoadModule unique_id_module lib/httpd/modules/mod_unique_id.so
<IfModule unique_id_module>
RequestHeader set unique_id %{UNIQUE_ID}e
</IfModule>
unique_id_module
はリクエストを識別するIDを生成する。これをHTTPヘッダunique_id
で共有。
httpd-proxy.conf
<Location /api/>
ProxyPass ajp://XXXXX:8090/
ProxyPassReverse ajp://XXXXX:8090/
</Location>
Tomcat Ajp設定
TomcatCustomizer.java
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.stereotype.Component;
@Component
public class TomcatCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
@Value("${tomcat.ajp.port:0}")
private int ajpPort;
@Override
public void customize(TomcatServletWebServerFactory factory) {
if (ajpPort != 0) {
factory.setProtocol("AJP/1.3");
factory.setPort(ajpPort);
}
}
}
SLF4J MDC設定
Apache httpdからHTTPヘッダで渡されたリクエストIDをMDCに格納。
もしなければ、代わりにランダムな文字列を生成する。
MdcConfig.java
import java.util.Base64;
import java.util.Random;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.MDC;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
@Configuration
public class MdcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new HandlerInterceptorAdapter() {
private Random random = new Random();
private static final String MDC_KEY_REQUEST_ID = "request_id";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String requestId = request.getHeader("unique_id");
if (requestId == null) {
requestId = generateRequestId();
}
MDC.put(MDC_KEY_REQUEST_ID, requestId);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
MDC.remove(MDC_KEY_REQUEST_ID);
}
private String generateRequestId() {
byte[] bytes = new byte[18];
random.nextBytes(bytes);
return Base64.getEncoder().encodeToString(bytes);
}
}).addPathPatterns("/*");
}
}
リクエストIDをログに含めるため、ログメッセージパターンに%X{request_id}
を指定する。
logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<appender name="MDC" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date{yyMMdd HH:mm:ss.SSS},%X{request_id},%m%n</pattern>
</encoder>
</appender>
<logger name="MDC" level="INFO">
<appender-ref ref="MDC" />
</logger>
</configuration>
Apache httpdアクセスログに含めるには、%{unique_id}e
httpd.conf
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"%{unique_id}e\"" combined
CustomLog "/usr/local/var/log/httpd/access_log" combined