Pub-Sub mesajlaşma

Merhaba!

Publish-Subcribe deseni, yazılım mimarisinde bileşenler arası mesajlaşmanın loosely-coupled ve asenkron olarak yapılmasını sağlayan bir yöntemdir.

Bulut bilişim’in son yıllarda gelişmesiyle birlikte birbirinden bağımsız ve kendi kendine yönetilebilir modüller yaygınlaştı. Pub-Sub deseni de cloud mimariye entegre olarak modüllerin birbiri ile haberleşmesinde kullanılabiliyor.

Observer vs Pub-Sub

Observer tasarım deseni ile benzer olmasına rağmen pub-sub’ın en önemli farkı publisher ve subscriber bileşenlerinin birbirinden haberi olmamasıdır. Bu sayede loosely-coupling kavramı sağlanmış olur. Oysa Observer deseninde observer ile observable nesneleri birbirine bağımlıdır. Bir diğer fark da Observer’ın senkron çalışması; Pub-Sub’ın asenkron olarak çalışabiliyor olmasıdır.

Bileşenler arası mesajlaşma, publisher ve subscriber arasında bulunan bir katman (message broker veya event bus) ile sağlanır. Bu katman publisher’dan gelen mesajları topic’lerine göre (topic-based system) veya mesaj içeriğine göre (content-based system) filtreleyerek, ilgili subscriber’lara iletir.

Örnek Pub-Sub Servis

Java ile örnek olması açısından basit bir pub-sub servis örneği oluşturdum. Publisher ve Subscriber class’ları belirli topicler üzerinden haberleşiyorlar.

Message

Message class’ı yalnızca topic ve mesaj içeren bir pojo.

public class Message {
private String topic;
private String message;
public Message(String topic, String message) {
this.topic = topic;
this.message = message;
}
public String getTopic() {
return topic;
}
public void setTopic(String topic) {
this.topic = topic;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@Override
public String toString() {
return "Message{" +
"topic='" + topic + '\'' +
", message='" + message + '\'' +
'}';
}
}
view raw Message.java hosted with ❤ by GitHub

Publisher

Publisher class’ı PubSubService ile bağımlı; Subscriber’lara herhangi bir bağımlılığı yok.

public class Publisher implements IPublisher {
private PubSubService pubSubService;
private String topic;
public Publisher(PubSubService pubSubService, String topic) {
this.pubSubService = pubSubService;
this.topic = topic;
}
@Override
public void publish(String message) {
pubSubService.publishMessage(new Message(topic, message));
}
}
view raw Publisher.java hosted with ❤ by GitHub

Subscriber

Aynı şekilde Subscriber class’ında da yalnızca PubSubService ile bağımlılık var.

public class Subscriber implements ISubscriber {
private PubSubService pubSubService;
private List<Message> messages;
public Subscriber(PubSubService pubSubService) {
this.pubSubService = pubSubService;
this.messages = new ArrayList<>();
}
@Override
public void subscribe(String topic) {
pubSubService.addSubscriberTo(topic, this);
}
@Override
public void unsubscribe(String topic) {
pubSubService.removeSubscriberFrom(topic, this);
}
@Override
public void printMessages() {
messages.forEach(System.out::println);
}
@Override
public void addMessage(Message message) {
messages.add(message);
}
}
view raw Subscriber.java hosted with ❤ by GitHub

PubSubService

PubSubService gelen mesajları topic’lerine göre ilgili subscriber’lara yönlendirmekle sorumlu.

public class PubSubService {
private Map<String, List<ISubscriber>> subscriberMap;
private Queue<Message> messageQueue;
public PubSubService() {
messageQueue = new LinkedList<>();
subscriberMap = new HashMap<>();
}
public void publishMessage(Message message) {
messageQueue.add(message);
}
public void broadcast() {
while(!messageQueue.isEmpty()) {
Message message = messageQueue.remove();
List<ISubscriber> subscribers = subscriberMap.get(message.getTopic());
if(subscribers != null) {
subscribers.forEach(s -> s.addMessage(message));
}
}
}
public void addSubscriberTo(String topic, Subscriber subscriber) {
List<ISubscriber> subscribers = subscriberMap.get(topic);
if(subscribers == null) {
subscribers = new ArrayList<>();
}
subscribers.add(subscriber);
subscriberMap.put(topic, subscribers);
}
public void removeSubscriberFrom(String topic, Subscriber subscriber) {
List<ISubscriber> subscribers = subscriberMap.get(topic);
if(subscribers != null) {
subscribers.remove(subscriber);
}
subscriberMap.put(topic, subscribers);
}
}
view raw PubSubService.java hosted with ❤ by GitHub

Uygulamanın çıktısını görebilmek için oluşturduğum Main class’ı;

public class Main {
public static void main(String[] args) {
PubSubService pubSubService = new PubSubService();
IPublisher musicPublisher = new Publisher(pubSubService, "music");
IPublisher newsPublisher = new Publisher(pubSubService, "news");
ISubscriber musicSubscriber = new Subscriber(pubSubService);
ISubscriber anotherMusicSubscriber = new Subscriber(pubSubService);
ISubscriber newsSubscriber = new Subscriber(pubSubService);
musicSubscriber.subscribe("music");
anotherMusicSubscriber.subscribe("music");
newsSubscriber.subscribe("news");
musicPublisher.publish("New album is coming.");
musicPublisher.publish("New concert!");
newsPublisher.publish("Brexit bla bla.");
pubSubService.broadcast();
System.out.println("Messages of music subscribers; ");
musicSubscriber.printMessages();
anotherMusicSubscriber.printMessages();
System.out.println("Messages of news subscribers; ");
newsSubscriber.printMessages();
}
}
view raw Main.java hosted with ❤ by GitHub

Çıktı

Messages of music subscribers; 
 Message{topic='music', message='New album is coming.'}
 Message{topic='music', message='New concert!'}
 Message{topic='music', message='New album is coming.'}
 Message{topic='music', message='New concert!'}
 Messages of news subscribers; 
 Message{topic='news', message='Brexit bla bla.'}

Bu uygulama asenkron çalışmıyor; ancak publisher ve subscriber birbirinden bağımsız olarak topic’ler üzerinden haberleşebildiler. Örnek uygulamanın tüm kodlarına buradan ulaşabilirsiniz.

Hoşçakalın!

Published by

Yusuf Kemal

Software Engineer

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s