Made TraceValve lazilly access beans. Fixes gh-2074

This commit is contained in:
Marcin Grzejszczak
2021-12-14 20:00:42 +01:00
parent 938a30af7e
commit c05a5d8175
3 changed files with 41 additions and 9 deletions

View File

@@ -29,6 +29,7 @@ import javax.servlet.ServletResponse;
import org.apache.catalina.Valve;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
@@ -102,7 +103,8 @@ class TraceWebServletConfiguration {
@Bean(name = CUSTOMIZER_NAME)
@Order(Ordered.HIGHEST_PRECEDENCE)
WebServerFactoryCustomizer<ConfigurableTomcatWebServerFactory> traceTomcatWebServerFactoryCustomizer(
HttpServerHandler httpServerHandler, CurrentTraceContext currentTraceContext) {
ObjectProvider<HttpServerHandler> httpServerHandler,
ObjectProvider<CurrentTraceContext> currentTraceContext) {
return factory -> factory.addEngineValves(new TraceValve(httpServerHandler, currentTraceContext));
}

View File

@@ -25,6 +25,7 @@ import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ValveBase;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.sleuth.CurrentTraceContext;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanCustomizer;
@@ -33,6 +34,7 @@ import org.springframework.cloud.sleuth.http.HttpServerHandler;
import org.springframework.cloud.sleuth.instrument.web.servlet.HttpServletRequestWrapper;
import org.springframework.cloud.sleuth.instrument.web.servlet.HttpServletResponseWrapper;
import org.springframework.core.log.LogAccessor;
import org.springframework.lang.NonNull;
/**
* A trace representation of a {@link Valve}.
@@ -44,28 +46,42 @@ public class TraceValve extends ValveBase {
private static final LogAccessor log = new LogAccessor(TraceValve.class);
private final HttpServerHandler httpServerHandler;
private HttpServerHandler httpServerHandler;
private final CurrentTraceContext currentTraceContext;
private CurrentTraceContext currentTraceContext;
public TraceValve(HttpServerHandler httpServerHandler, CurrentTraceContext currentTraceContext) {
private final ObjectProvider<HttpServerHandler> httpServerHandlerProvider;
private final ObjectProvider<CurrentTraceContext> currentTraceContextProvider;
public TraceValve(@NonNull HttpServerHandler httpServerHandler, @NonNull CurrentTraceContext currentTraceContext) {
this.httpServerHandler = httpServerHandler;
this.currentTraceContext = currentTraceContext;
this.httpServerHandlerProvider = null;
this.currentTraceContextProvider = null;
setAsyncSupported(true);
}
public TraceValve(@NonNull ObjectProvider<HttpServerHandler> httpServerHandler,
@NonNull ObjectProvider<CurrentTraceContext> currentTraceContext) {
this.httpServerHandler = null;
this.currentTraceContext = null;
this.httpServerHandlerProvider = httpServerHandler;
this.currentTraceContextProvider = currentTraceContext;
setAsyncSupported(true);
}
@Override
public void invoke(Request request, Response response) throws IOException, ServletException {
Exception ex = null;
Span handleReceive = this.httpServerHandler
.handleReceive(HttpServletRequestWrapper.create(request.getRequest()));
Span handleReceive = httpServerHandler().handleReceive(HttpServletRequestWrapper.create(request.getRequest()));
if (log.isDebugEnabled()) {
log.debug("Created a server receive span [" + handleReceive + "]");
}
request.setAttribute(SpanCustomizer.class.getName(), handleReceive);
request.setAttribute(TraceContext.class.getName(), handleReceive.context());
request.setAttribute(Span.class.getName(), handleReceive);
try (CurrentTraceContext.Scope ws = this.currentTraceContext.maybeScope(handleReceive.context())) {
try (CurrentTraceContext.Scope ws = currentTraceContext().maybeScope(handleReceive.context())) {
Valve next = getNext();
if (null == next) {
// no next valve
@@ -78,7 +94,7 @@ public class TraceValve extends ValveBase {
throw exception;
}
finally {
this.httpServerHandler.handleSend(
httpServerHandler().handleSend(
HttpServletResponseWrapper.create(request.getRequest(), response.getResponse(), ex), handleReceive);
if (log.isDebugEnabled()) {
log.debug("Handled send of span [" + handleReceive + "]");
@@ -86,4 +102,18 @@ public class TraceValve extends ValveBase {
}
}
private HttpServerHandler httpServerHandler() {
if (this.httpServerHandler == null) {
this.httpServerHandler = this.httpServerHandlerProvider.getIfAvailable();
}
return this.httpServerHandler;
}
private CurrentTraceContext currentTraceContext() {
if (this.currentTraceContext == null) {
this.currentTraceContext = this.currentTraceContextProvider.getIfAvailable();
}
return this.currentTraceContext;
}
}

View File

@@ -68,7 +68,7 @@ class TraceValveTests {
@Test
void should_have_async_supported_by_default() throws ServletException, IOException {
TraceValve traceValve = new TraceValve(null, null);
TraceValve traceValve = new TraceValve((HttpServerHandler) null, null);
BDDAssertions.then(traceValve.isAsyncSupported()).isTrue();
}