treat the 'destination' param as path while match using a PathMatcher
Specifically an AntPathMatcher with the separator as a colon (:) fixes gh-17
This commit is contained in:
@@ -16,6 +16,10 @@ include::quickstart.adoc[]
|
||||
|
||||
The HTTP endpoints accept a "destination" parameter, e.g. "/bus/refresh?destination=customers:9000", where the destination is an `ApplicationContext` ID. If the ID is owned by an instance on the Bus then it will process the message and all other instances will ignore it. Spring Boot sets the ID for you in the `ContextIdApplicationContextInitializer` to a combination of the `spring.application.name`, active profiles and `server.port` by default.
|
||||
|
||||
== Addressing all instances of a service
|
||||
|
||||
The "destination" parameter is used in a Spring `PathMatcher` (with the path separator as a colon `:`) to determine if an instance will process the message. Using the example from above, "/bus/refresh?destination=customers:**" will target all instances of the "customers" service regardless of the profiles and ports set as the `ApplicationContext` ID.
|
||||
|
||||
== Customizing the AMQP ConnectionFactory
|
||||
|
||||
If you are using AMQP there needs to be a `ConnectionFactory` (from
|
||||
|
||||
@@ -30,6 +30,8 @@ import org.springframework.integration.event.outbound.ApplicationEventPublishing
|
||||
import org.springframework.integration.handler.LoggingHandler;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.SubscribableChannel;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.PathMatcher;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
@@ -54,7 +56,7 @@ public class BusAutoConfiguration {
|
||||
return new GenericSelector<RemoteApplicationEvent>() {
|
||||
@Override
|
||||
public boolean accept(RemoteApplicationEvent source) {
|
||||
return isFromSelf(source);
|
||||
return serviceMatcher().isFromSelf(source);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -85,7 +87,7 @@ public class BusAutoConfiguration {
|
||||
return new GenericSelector<RemoteApplicationEvent>() {
|
||||
@Override
|
||||
public boolean accept(RemoteApplicationEvent event) {
|
||||
return !isFromSelf(event) && isForSelf(event);
|
||||
return !serviceMatcher().isFromSelf(event) && serviceMatcher().isForSelf(event);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -115,6 +117,16 @@ public class BusAutoConfiguration {
|
||||
return IntegrationFlows.from(cloudBusWiretapChannel()).handle(handler).get();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PathMatcher busPathMatcher() {
|
||||
return new AntPathMatcher(":");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ServiceMatcher serviceMatcher() {
|
||||
return new ServiceMatcher();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(Endpoint.class)
|
||||
protected static class BusEndpointConfiguration {
|
||||
@@ -169,20 +181,6 @@ public class BusAutoConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isFromSelf(RemoteApplicationEvent event) {
|
||||
String originService = event.getOriginService();
|
||||
String serviceId = getServiceId();
|
||||
return originService.equals(serviceId);
|
||||
}
|
||||
|
||||
private boolean isForSelf(RemoteApplicationEvent event) {
|
||||
return (event.getDestinationService() == null
|
||||
|| event.getDestinationService().trim().isEmpty() || event
|
||||
.getDestinationService().equals(getServiceId()));
|
||||
}
|
||||
|
||||
private String getServiceId() {
|
||||
return context.getId();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.springframework.cloud.bus;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.cloud.bus.event.RemoteApplicationEvent;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.util.PathMatcher;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class ServiceMatcher implements ApplicationContextAware {
|
||||
private ApplicationContext context;
|
||||
private PathMatcher matcher;
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext context) throws BeansException {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
@Qualifier("busPathMatcher")
|
||||
public void setMatcher(PathMatcher matcher) {
|
||||
this.matcher = matcher;
|
||||
}
|
||||
|
||||
public boolean isFromSelf(RemoteApplicationEvent event) {
|
||||
String originService = event.getOriginService();
|
||||
String serviceId = getServiceId();
|
||||
return matcher.match(originService, serviceId);
|
||||
}
|
||||
|
||||
public boolean isForSelf(RemoteApplicationEvent event) {
|
||||
String destinationService = event.getDestinationService();
|
||||
return (destinationService == null || destinationService.trim().isEmpty() || matcher
|
||||
.match(destinationService, getServiceId()));
|
||||
}
|
||||
|
||||
private String getServiceId() {
|
||||
return context.getId();
|
||||
}
|
||||
}
|
||||
@@ -75,6 +75,36 @@ public class BusAutoConfigurationTests {
|
||||
assertNull(context.getBean(OutboundMessageHandlerConfiguration.class).message);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inboundNotFromSelfPathPattern() {
|
||||
context = SpringApplication.run(InboundMessageHandlerConfiguration.class);
|
||||
context.setId("bar:1000");
|
||||
context.getBean("cloudBusInboundChannel", MessageChannel.class).send(
|
||||
new GenericMessage<>(new RefreshRemoteApplicationEvent(this, "foo",
|
||||
"bar:*")));
|
||||
assertNotNull(context.getBean(InboundMessageHandlerConfiguration.class).event);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inboundNotFromSelfDeepPathPattern() {
|
||||
context = SpringApplication.run(InboundMessageHandlerConfiguration.class);
|
||||
context.setId("bar:test:1000");
|
||||
context.getBean("cloudBusInboundChannel", MessageChannel.class).send(
|
||||
new GenericMessage<>(new RefreshRemoteApplicationEvent(this, "foo",
|
||||
"bar:**")));
|
||||
assertNotNull(context.getBean(InboundMessageHandlerConfiguration.class).event);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inboundNotFromSelfFlatPattern() {
|
||||
context = SpringApplication.run(InboundMessageHandlerConfiguration.class);
|
||||
context.setId("bar");
|
||||
context.getBean("cloudBusInboundChannel", MessageChannel.class).send(
|
||||
new GenericMessage<>(new RefreshRemoteApplicationEvent(this, "foo",
|
||||
"bar*")));
|
||||
assertNotNull(context.getBean(InboundMessageHandlerConfiguration.class).event);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import(BusAutoConfiguration.class)
|
||||
@MessageEndpoint
|
||||
|
||||
Reference in New Issue
Block a user