|
| 1 | +--- |
| 2 | +title: "Publish/Subscribe" |
| 3 | +shortTitle: "Pub/Sub Pattern" |
| 4 | +description: "A messaging pattern that enables loose coupling between publishers and subscribers through message topics" |
| 5 | +category: Behavioral |
| 6 | +language: en |
| 7 | +tag: |
| 8 | + - Messaging |
| 9 | + - Event-Driven |
| 10 | + - Decoupling |
| 11 | +--- |
| 12 | + |
| 13 | +## Also known as |
| 14 | + |
| 15 | +- Pub/Sub |
| 16 | +- Observer Pattern (similar but not identical) |
| 17 | + |
| 18 | +## Intent |
| 19 | + |
| 20 | +Establish a one-to-many, many-to-one, or many-to-many dependency between objects where multiple publishers send messages to topics, and multiple subscribers can receive those messages without direct knowledge of each other, promoting loose coupling and scalability. |
| 21 | + |
| 22 | +## Core Concepts |
| 23 | + |
| 24 | +### Topics and Messaging Components |
| 25 | + |
| 26 | +A topic is a distribution mechanism for publishing messages between message producers and message consumers in a one-to-many relationship. Key components include: |
| 27 | + |
| 28 | +- **Topics**: Destinations where publishers send messages and from which subscribers receive them. Unlike queues (used in point-to-point messaging), topics can have multiple consumers. |
| 29 | + |
| 30 | +- **Message Producers**: Lightweight objects created to send messages to a topic. They are typically created per topic and can be created for each message since they don't consume significant resources. |
| 31 | + |
| 32 | +- **Message Consumers**: Objects that subscribe to topics and receive messages. Consumers can receive messages either: |
| 33 | + - Synchronously: By calling a `receive()` method that blocks until a message arrives |
| 34 | + - Asynchronously: By implementing a message listener with an `onMessage()` callback (which is discussed in this implementation) |
| 35 | + |
| 36 | +### Types of Subscriptions |
| 37 | + |
| 38 | +1. **Non-Durable Subscriptions** |
| 39 | + |
| 40 | + - Simplest form of subscription |
| 41 | + - Exists only while the consumer is active |
| 42 | + - Messages sent while the subscriber is inactive are missed |
| 43 | + - Best for real-time data where missing messages is acceptable |
| 44 | + - Example: Live sports score updates |
| 45 | + |
| 46 | +2. **Durable Subscriptions** |
| 47 | + |
| 48 | + - Maintains subscription state even when subscriber is offline |
| 49 | + - Messages are stored by JMS provider until consumer reconnects |
| 50 | + - Requires a unique client identifier for persistence |
| 51 | + - Two subtypes: |
| 52 | + - Unshared: Only one consumer can use the subscription |
| 53 | + - Shared: Multiple consumers can share the subscription |
| 54 | + - Example: Critical business notifications |
| 55 | + |
| 56 | +3. **Shared Subscriptions** |
| 57 | + - Allows multiple consumers to share message load |
| 58 | + - Messages are distributed among active consumers |
| 59 | + - Can be combined with durability |
| 60 | + - Useful for load balancing and high-throughput scenarios |
| 61 | + - Example: Distributed processing of bank transactions |
| 62 | + |
| 63 | +### Messaging Infrastructure |
| 64 | + |
| 65 | +The JMS (Java Message Service) provider handles: |
| 66 | + |
| 67 | +- Message persistence for durable subscriptions |
| 68 | +- Message distribution to appropriate subscribers |
| 69 | +- Connection and session management |
| 70 | +- Transaction support when integrated with JTA |
| 71 | +- Load balancing for shared subscriptions |
| 72 | + |
| 73 | +## Detailed Explanation with Real-World Examples |
| 74 | + |
| 75 | +Real-world example |
| 76 | + |
| 77 | +> Consider a news distribution system where different types of subscribers receive news updates: |
| 78 | +> |
| 79 | +> - Regular subscribers who only receive messages while they're online |
| 80 | +> - Durable subscribers who receive missed messages when they reconnect |
| 81 | +> - Shared subscribers who distribute the message load among multiple instances |
| 82 | +> This is exactly what our demonstration implements in the App.java examples. |
| 83 | +
|
| 84 | +In plain words |
| 85 | + |
| 86 | +> A news publishing system where publishers can send news to topics, and different types of subscribers (basic, durable, shared) can receive these updates in various ways, as demonstrated in our three main scenarios: basic publish-subscribe, durable subscriptions, and shared subscriptions. |
| 87 | +
|
| 88 | +Wikipedia says |
| 89 | + |
| 90 | +> Publish–subscribe is a messaging pattern where senders of messages, called publishers, do not program the messages to be sent directly to specific receivers, called subscribers, but instead categorize published messages into classes without knowledge of which subscribers, if any, may be interested. |
| 91 | +
|
| 92 | +## Programmatic Example |
| 93 | + |
| 94 | +### 1. Basic Publish-Subscribe Pattern |
| 95 | + |
| 96 | +The most straightforward implementation where all subscribers receive all messages: |
| 97 | + |
| 98 | +```java |
| 99 | +// Create basic subscribers that receive messages only while online |
| 100 | +TopicSubscriber basicSub1 = new TopicSubscriber( |
| 101 | + "BasicSub1", "NEWS", SubscriberType.NONDURABLE, null |
| 102 | +); |
| 103 | +TopicSubscriber basicSub2 = new TopicSubscriber( |
| 104 | + "BasicSub2", "NEWS", SubscriberType.NONDURABLE, null |
| 105 | +); |
| 106 | + |
| 107 | +// Create publisher and send messages |
| 108 | +TopicPublisher publisher = new TopicPublisher("NEWS"); |
| 109 | +publisher.publish(new Message("Basic message 1", "NEWS")); |
| 110 | +publisher.publish(new Message("Basic message 2", "NEWS")); |
| 111 | + |
| 112 | +// Both BasicSub1 and BasicSub2 will receive all messages |
| 113 | +``` |
| 114 | + |
| 115 | +### 2. Durable Subscriptions Pattern |
| 116 | + |
| 117 | +Demonstrates how subscribers can receive messages that were published while they were offline: |
| 118 | + |
| 119 | +```java |
| 120 | +// Create durable subscriber with client ID for persistence |
| 121 | +TopicSubscriber durableSub = new TopicSubscriber( |
| 122 | + "DurableSub", "NEWS", SubscriberType.DURABLE, "durable-client" |
| 123 | +); |
| 124 | + |
| 125 | +// First message - subscriber receives while online |
| 126 | +publisher.publish(new Message("Durable message while online", "NEWS")); |
| 127 | + |
| 128 | +// Subscriber goes offline (close connection) |
| 129 | +durableSub.close(); |
| 130 | + |
| 131 | +// Message sent while subscriber is offline |
| 132 | +publisher.publish(new Message("Durable message while offline", "NEWS")); |
| 133 | + |
| 134 | +// When subscriber reconnects, it receives the missed message |
| 135 | +durableSub = new TopicSubscriber( |
| 136 | + "DurableSub", "NEWS", SubscriberType.DURABLE, "durable-client" |
| 137 | +); |
| 138 | +``` |
| 139 | + |
| 140 | +### 3. Shared Subscriptions Pattern |
| 141 | + |
| 142 | +Shows how messages can be distributed among multiple subscribers for load balancing: |
| 143 | + |
| 144 | +```java |
| 145 | +// Create shared subscribers that will distribute the message load |
| 146 | +TopicSubscriber sharedSub1 = new TopicSubscriber( |
| 147 | + "SharedSub1", "NEWS", SubscriberType.SHARED, null |
| 148 | +); |
| 149 | +TopicSubscriber sharedSub2 = new TopicSubscriber( |
| 150 | + "SharedSub2", "NEWS", SubscriberType.SHARED, null |
| 151 | +); |
| 152 | + |
| 153 | +// Send multiple messages that will be distributed |
| 154 | +publisher.publish(new Message("Shared message 1", "NEWS")); |
| 155 | +publisher.publish(new Message("Shared message 2", "NEWS")); |
| 156 | +publisher.publish(new Message("Shared message 3", "NEWS")); |
| 157 | +publisher.publish(new Message("Shared message 4", "NEWS")); |
| 158 | + |
| 159 | +// Messages are distributed between SharedSub1 and SharedSub2 |
| 160 | +// Each subscriber receives approximately half of the messages |
| 161 | +``` |
| 162 | + |
| 163 | +## Implementation Details |
| 164 | + |
| 165 | +- Basic subscribers demonstrate the simplest form of pub/sub where all subscribers receive all messages |
| 166 | +- Durable subscribers maintain their subscription state even when offline, ensuring no messages are missed |
| 167 | +- Shared subscribers enable load balancing by distributing messages among multiple consumers |
| 168 | +- Messages are delivered asynchronously through the `onMessage()` callback |
| 169 | +- The JMS provider (ActiveMQ in this implementation) handles message persistence and distribution |
| 170 | + |
| 171 | +## When to Use |
| 172 | + |
| 173 | +- When you need different types of message consumption patterns: |
| 174 | + - Basic subscribers for simple real-time updates |
| 175 | + - Durable subscribers for critical messages that can't be missed |
| 176 | + - Shared subscribers for load balancing |
| 177 | +- When subscribers need to receive messages even after being offline (demonstrated in durableSubscriptions() example) |
| 178 | +- When message load needs to be distributed among multiple consumers (demonstrated in sharedSubscriptions() example) |
| 179 | + |
| 180 | +## Real-World Applications |
| 181 | + |
| 182 | +Any event-driven system that requires loose coupling between publishers and subscribers can benefit from the pub/sub pattern. Some common examples include: |
| 183 | + |
| 184 | +- IOT systems where multiple devices publish data to a central server |
| 185 | +- Enterprise messaging systems (JMS) for inter-application communication |
| 186 | +- Microservices architectures where services communicate through message brokers |
| 187 | +- News distribution systems (as demonstrated in our NEWS topic example) |
| 188 | +- Load-balanced message processing systems (using shared subscriptions) |
| 189 | +- Message broadcasting systems (using basic pub/sub) |
| 190 | + |
| 191 | +## Benefits and Trade-offs |
| 192 | + |
| 193 | +Benefits: |
| 194 | + |
| 195 | +- Loose coupling between publishers and subscribers |
| 196 | +- Scalability through message distribution |
| 197 | +- Flexibility to add/remove components |
| 198 | +- Support for offline components through durable subscriptions |
| 199 | +- Asynchronous communication |
| 200 | + |
| 201 | +Trade-offs: |
| 202 | + |
| 203 | +- Additional complexity in message delivery guarantees |
| 204 | +- Potential performance overhead from message broker |
| 205 | +- Message ordering challenges in distributed systems |
| 206 | +- Durable subscriptions which allow for message persistence add a coniderable overhead |
| 207 | + |
| 208 | +## Related Patterns |
| 209 | + |
| 210 | +- Observer Pattern |
| 211 | +- Mediator Pattern |
| 212 | +- Event Sourcing |
| 213 | +- Message Queue Pattern |
| 214 | + |
| 215 | +## References |
| 216 | + |
| 217 | +- Java EE Tutorial - JMS Messaging |
| 218 | +- Enterprise Integration Patterns |
0 commit comments