The term ‘subscription’ in Reactor Service Bus is a bit overloaded. It means more than the latter half of a typical pub/sub pattern. We use the term ‘subscription’ to signify any interest an endpoint has in any message type, and what channel they wish to receive it on.
Destinations
The JMS specification is written to provide two destinations on which an endpoint can receive a message. They are Topics and Queues. The diagrams below depict the standard purpose of Topics and Queues.
* – Typical pub/sub pattern using Topics
* – Typical point-to-point communication using Queues
Fairly straight forward when you look at it in terms of pub/sub or point-to-point. There are additional complexities in how each are implemented and their capabilities, such as what happens when you have multiple recipients listening to the same queue?
Important concepts surrounding Topics:
Important concepts surrounding Queues:
As previously mentioned, the term ‘subscription’ in Reactor is overloaded and not limited to pub/sub models. Rather, it indicates an interest in a particular message type on a particular destination (Queue or Topic). In the next section, we’ll discuss how this interest is declared and formalized.
Declaring Subscriptions
One of the goals of Reactor Service Bus was to declare subscriptions simply by defining message handlers and not by manually calling methods to subscribe. Of course, this behavior can be overridden, where a handler opts out of automatic subscription and allows code to manually initiate a subscription. Let’s cover automatic subscriptions first.
Automatic subscriptions are achieved by simply decorating a message handler with the appropriate destination attribute. The two attributes are:
If a message handler does not contain one of these attributes, no automatic subscription is performed. If a destination attribute is present, a subscription is created for the specified destination and registered with the configured IDestinationRegistry instance.
Destination attributes convey destination names both implicitly and explicitly. The rules around this are simple:
Here is an example of a handler declaration that expects a “UserCreated” event message on the topic: CompanyXYZ.Events.UserCreated:
[Topic] public class UserCreatedHandler : IMessageHandler<CompanyXYZ.Events.UserCreated> { // Implementation }
Note: The same handler decorated with the [Queue] attribute would expect messages of that type to be received on the primary input queue.
We don’t always have the luxury of creating message types whose full namespace with type name can act as a meaningful subscription topic name. For these occasions, we can override the default topic for a message like this:
[Topic("CompanyXYZ.HumanResources.Events.UserCreated")] public class UserCreatedHandler : IMessageHandler<UserCreated> { // Implementation }
Similarly, overriding the implicit queue name is performed the same way as topics.