Ensure message headers are still mutable after interceptor is called

Some components in Spring assume (perhaps wrongly) that a channel
interceptor will not convert a mutable message into an immutable
one, and they continue to modify the headers dowstream. We can
dosge the issue of whether this is right or wrong by keeping the
message headers mutable, just in case.

It would probably be better to refactor the SpanInjector so that
it works with something other than the MessageBuilder, but we can
defer doing that in favour of this smaller change that works.

Adds a test for mutability. Also tested with the
gs-messaging-stomp-websocket guide from spring.io.

Fixes gh-276
This commit is contained in:
Dave Syer
2016-10-10 13:27:53 +01:00
parent 5080ee3e24
commit 1d1f28d971
2 changed files with 15 additions and 1 deletions

View File

@@ -26,7 +26,9 @@ import org.springframework.cloud.sleuth.sampler.NeverSampler;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.messaging.support.MessageHeaderAccessor;
/**
* A channel interceptor that automatically starts / continues / closes and detaches
@@ -84,7 +86,9 @@ public class TraceChannelInterceptor extends AbstractTraceChannelInterceptor {
messageBuilder.setHeader(TraceMessageHeaders.MESSAGE_SENT_FROM_CLIENT, true);
}
getSpanInjector().inject(span, messageBuilder);
return messageBuilder.build();
MessageHeaderAccessor headers = MessageHeaderAccessor.getMutableAccessor(message);
headers.copyHeaders(messageBuilder.build().getHeaders());
return new GenericMessage<Object>(message.getPayload(), headers.getMessageHeaders());
}
private Span startSpan(Span span, String name, Message<?> message) {

View File

@@ -44,6 +44,7 @@ import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.support.MessageHeaderAccessor;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -117,6 +118,15 @@ public class TraceChannelInterceptorTests implements MessageHandler {
then(this.span.isExportable()).isFalse();
}
@Test
public void messageHeadersStillMutable() {
this.tracedChannel.send(MessageBuilder.withPayload("hi")
.setHeader(Span.SAMPLED_NAME, Span.SPAN_NOT_SAMPLED).build());
assertNotNull("message was null", this.message);
MessageHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(this.message, MessageHeaderAccessor.class);
assertNotNull("Message header accessor should be still available", accessor);
}
@Test
public void parentSpanIncluded() {
this.tracedChannel.send(MessageBuilder.withPayload("hi")