Add ImmutableMessageChannelInterceptor
This change adds a ChannelInterceptor that flips the immutable flag on messages being sent. This allows components sending messages to leave the message mutable for interceptors to further apply modifications before the message is sent (and exposed to concurrency). The interceptor is automatically added with the STOMP/WebSocket Java and XML config and the StompSubProtocolHandler leaves parsed incoming messages mutable so they can be further modified before being sent. Issue: SPR-12321
This commit is contained in:
@@ -21,6 +21,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.messaging.support.ImmutableMessageChannelInterceptor;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
@@ -201,11 +202,14 @@ class MessageBrokerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
argValues.addIndexedArgumentValue(0, new RuntimeBeanReference(executorName));
|
||||
}
|
||||
RootBeanDefinition channelDef = new RootBeanDefinition(ExecutorSubscribableChannel.class, argValues, null);
|
||||
ManagedList<? super Object> interceptors = new ManagedList<Object>();
|
||||
if (element != null) {
|
||||
Element interceptorsElement = DomUtils.getChildElementByTagName(element, "interceptors");
|
||||
ManagedList<?> interceptors = WebSocketNamespaceUtils.parseBeanSubElements(interceptorsElement, context);
|
||||
channelDef.getPropertyValues().add("interceptors", interceptors);
|
||||
interceptors.addAll(WebSocketNamespaceUtils.parseBeanSubElements(interceptorsElement, context));
|
||||
}
|
||||
interceptors.add(new ImmutableMessageChannelInterceptor());
|
||||
channelDef.getPropertyValues().add("interceptors", interceptors);
|
||||
|
||||
registerBeanDefByName(name, channelDef, context, source);
|
||||
return new RuntimeBeanReference(name);
|
||||
}
|
||||
|
||||
@@ -45,6 +45,9 @@ import org.springframework.messaging.simp.stomp.StompEncoder;
|
||||
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
|
||||
import org.springframework.messaging.simp.user.DestinationUserNameProvider;
|
||||
import org.springframework.messaging.simp.user.UserSessionRegistry;
|
||||
import org.springframework.messaging.support.AbstractMessageChannel;
|
||||
import org.springframework.messaging.support.ChannelInterceptor;
|
||||
import org.springframework.messaging.support.ImmutableMessageChannelInterceptor;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.messaging.support.MessageHeaderAccessor;
|
||||
import org.springframework.messaging.support.MessageHeaderInitializer;
|
||||
@@ -99,6 +102,8 @@ public class StompSubProtocolHandler implements SubProtocolHandler, ApplicationE
|
||||
|
||||
private MessageHeaderInitializer headerInitializer;
|
||||
|
||||
private Boolean immutableMessageInterceptorPresent;
|
||||
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
|
||||
private final Stats stats = new Stats();
|
||||
@@ -234,7 +239,9 @@ public class StompSubProtocolHandler implements SubProtocolHandler, ApplicationE
|
||||
headerAccessor.setSessionId(session.getId());
|
||||
headerAccessor.setSessionAttributes(session.getAttributes());
|
||||
headerAccessor.setUser(session.getPrincipal());
|
||||
headerAccessor.setImmutable();
|
||||
if (!detectImmutableMessageInterceptor(outputChannel)) {
|
||||
headerAccessor.setImmutable();
|
||||
}
|
||||
|
||||
if (StompCommand.CONNECT.equals(headerAccessor.getCommand())) {
|
||||
this.stats.incrementConnectCount();
|
||||
@@ -271,6 +278,22 @@ public class StompSubProtocolHandler implements SubProtocolHandler, ApplicationE
|
||||
}
|
||||
}
|
||||
|
||||
private boolean detectImmutableMessageInterceptor(MessageChannel channel) {
|
||||
if (this.immutableMessageInterceptorPresent != null) {
|
||||
return this.immutableMessageInterceptorPresent;
|
||||
}
|
||||
if (channel instanceof AbstractMessageChannel) {
|
||||
for (ChannelInterceptor interceptor : ((AbstractMessageChannel) channel).getInterceptors()) {
|
||||
if (interceptor instanceof ImmutableMessageChannelInterceptor) {
|
||||
this.immutableMessageInterceptorPresent = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.immutableMessageInterceptorPresent = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void publishEvent(ApplicationEvent event) {
|
||||
try {
|
||||
this.eventPublisher.publishEvent(event);
|
||||
|
||||
Reference in New Issue
Block a user