Напишете собствената си МАМА!

МАМА е неразбрана и МАМА не получава кредит. Може би сте чували това и преди, но в арената на разпределените системи това всъщност е вярно! Това е така, защото ориентираният към съобщения междинен софтуер (MOM) традиционно не се радва на същото ниво на изтънченост и поддръжка като другите технологии, използвани в разпределените комуникационни рамки.

Но времената се променят. С въвеждането на сложни, стабилни предложения на доставчици, интересът към MOM системите нараства бързо. Добрите внедрения на MOM осигуряват интерфейс за приложения на високо ниво, гаранции за качество на услугата и множество услуги като сигурност, опашки за съобщения и поддръжка на директории, които са необходими за разпределени комуникации с „индустриална сила“.

Разпределени комуникационни рамки

Целта на разпределената комуникационна рамка е да осигури добър начин за комуникация на частите на разпределена система. Обектно-ориентираните рамки изпълняват тази задача, като предоставят на разпределените обекти начин да си обменят съобщения.

Разпределените обектно-ориентирани рамки, които привличат най-много внимание, са тези, които моделират съобщенията като извиквания на методи. CORBA и RMI са два отлични примера за този тип рамка (вж. Ресурси). Тези системи често се наричат ​​системи за отдалечено извикване на процедури (RPC). Магията на тези системи е, че те правят, че извикванията за отдалечени процедури (или методи) изглежда са локални извиквания на процедури (LPC).

RPC се архитират върху клиент / сървърния модел. Например обектите CORBA, които излагат методи, които да бъдат извикани от отдалечени обекти, се наричат ​​(и са) сървъри.

Представяме ви МАМА

За разлика от RPC, MOM не моделират съобщения като извиквания на методи; вместо това те ги моделират като събития в система за доставка на събития. Клиентите изпращат и получават събития или „съобщения“ чрез API, които MOM предоставя. MOM може да представи каталожни услуги, които позволяват на клиентите да търсят друго приложение, което действа като сървър, или може да представи универсални „канали“, които позволяват на група клиенти да комуникират като връстници, или може да представи и двете опции.

Всички приложения комуникират директно помежду си с помощта на MOM. Съобщенията, генерирани от приложения, имат значение само за други клиенти, тъй като самата MOM е само рутер за съобщения (а в някои случаи и система за опашка на съобщения).

MOMs се предлагат във всякакви форми и размери

Всички MOM споделят две основни характеристики: те позволяват предаването на съобщения и предаването на съобщения не се блокира. Освен тези основи, доставчиците могат да внедрят произволен брой различни интерфейси и услуги.

Много MOM предоставят интерфейс за публикуване и абониране, за да позволят на приложенията да публикуват и получават съобщения, които ги интересуват. Този интерфейс може да бъде под формата на система, базирана на канали, или по-проста система, в която клиент регистрира видовете съобщения интересува се от получаване.

Основните MOM предоставят само директни съобщения, без допълнителни услуги. Усъвършенстваните MOM осигуряват опашки за съобщения и гарантирана доставка, заедно със сигурността, междуплатформеното разпределяне на данни, мащабируемостта и други предимства.

МАМИ с един поглед

Ето кратка справка, която ще ви помогне да разберете какво представляват MOMs.

Предимства на MOM

  • Просто : Клиентите публикуват и се абонират

    публикувай и се абонирай е полезна абстракция на високо ниво за това, което приложенията трябва да направят, за да комуникират.

  • Лесно : Не се изисква сложна настройка

    MOMs са лесни за инсталиране и използване, за разлика от сложните RPC-базирани системи като CORBA.

  • Общо : Една и съща MOM може да се използва за множество приложения

    Тъй като всяка дадена MOM система по същество е само общ транспорт на съобщения, тя може да бъде използвана повторно в различни приложения без допълнителна работа.

  • Гъвкаво : Може да се предава всеки вид съобщение

    Всяко съобщение може да бъде предадено от MOM. Тъй като МАМАТА не разбира съобщенията, няма значение какви са те.

MOM недостатъци

  • Общи : Приложенията трябва да разбират съобщенията

    Принуждаването на приложенията да използват съобщения вместо извиквания на методи може да бъде сложно, особено ако приложението разчита на факта, че извикванията на метода блокират.

  • Непознато : Не моделира извиквания на методи

    Разработчиците, които не са запознати със съобщенията, може да имат проблеми при измислянето на начина, по който да ги използват ефективно.

  • Асинхронно : Съобщенията не се блокират

    Съобщенията естествено не блокират. Това затруднява писането на приложения, които се нуждаят от блокиране на обаждания.

  • Твърде просто : Няма разпределяне на данни

    Дори простите RPC системи правилно разпределят данните. Обикновените MOM могат просто да изпращат съобщения, в които байтовете не са в ред от гледна точка на получателя.

  • Нестандартни : Доставчиците са навсякъде

    Реализациите на MOM на доставчика правят всичко ... и нищо.

    Риск на купувача

    е фразата, която трябва да имате предвид, когато преглеждате различните предложения на доставчици.

Кога са подходящи MOMs?

  • При общуване приложенията трябва да използват съобщения
  • Когато персоналът за програмиране не е свързан с клиент / сървър и RPC системи
  • Когато CORBA / RMI и свързаните с тях системи са твърде сложни
  • Когато простите RPC системи са твърде елементарни

Съображения за дизайна на нашата MOM

Сега, когато фонът е изчезнал, нека започнем да сглобяваме нашата MOM, Message Bus . Ще използваме MOM, за да дадем възможност за комуникация между клиенти на разпределена дъска. (Вижте Ресурси за връзки към информация за приложението за бяла дъска, с което работихме през последните няколко вноски.)

Основното съображение за шината за съобщения е, че тя осигурява удобен интерфейс за комуникация на високо ниво към обектите на приложението, които ще я използват.

Because a channel makes sense as the central service that the Message Bus should provide, the interface to the Message Bus is the Channel class. The client uses the Channel class to access every high-level function of the Message Bus, from subscribing and publishing to listing available channels in the system.

The Channel class exposes class methods that affect the Message Bus as a whole, or pertain to all channels. Each channel instance represents a single channel in the system and exposes channel-specific methods.

Two interfaces, ChannelListener and ChannelsUpdateListener, are provided for the purposes of subscribing to receive messages on a channel and receiving notification of channel addition, respectively.

The image below illustrates the Message Bus system architecture.

Under the hood

Under the hood, the Message Bus application uses class methods and data structures of

Channel

to keep track of channels. Listeners to a channel implement the

ChannelListener

interface, and objects that want to receive updates about channel adds implement the

ChannelsUpdateListener

interface. Registered listener objects are called back by

Channel

whenever anything interesting happens. All communication with the outside world is done with a transport-specific implementation of the

MessageBus

interface, such as

MessageBusSocketImpl

.

Each MessageBus implementation passes messages by talking to a corresponding message-passing server, called a broker, over a shared network transport such as sockets or URL/servlets. The broker routes messages among MessageBus instances, each of which corresponds to a Channel class.

Because these transport-specific implementations all implement the MessageBus interface, they are interchangeable. For example, a servlet-based MessageBus and broker can be used by Channel in place of the sockets-based MessageBus and broker.

Our Message Bus is a simple peer-to-peer system based on channels, making it suitable for use in a peer-to-peer application such as a collaborative system.

Using the Message Bus in a client application

These steps allow a client to use the Message Bus:

  1. Set up an instance of MessageBus.

     Channel.setMessageBus (new MessageBusSocketImpl (BROKER_NAME, BROKER_PORT)); 

    In this call, a new MessageBus implementation is created, with the broker identified by the arguments to the constructor call.

  2. Subscribe to a channel.

     Channel textChannel = Channel.subscribe ("text_channel", this); 

    This call returns an instance of the channel corresponding to the channel name argument. If the channel does not exist, it is created in the system.

    Passing this as an argument means that that caller is itself a ChannelListener. The caller can subscribe not just itself but any ChannelListener to the channel, or any number of listeners to a single channel.

  3. Publish a message to the channel.

     textChannel.publish (new String (myID + " says Hello!")); 

    Publishing a message is easy and entails nothing more than calling publish() on the chosen channel instance. Note that the message can be any type of object, as long as other clients on the channel can understand it, and the server has access to the message class file(s) (as detailed in the Using the Message Bus section)

Additional optional steps include:

  • Unsubscribe a listener from a channel.

     textChannel.unsubscribe (ChannelListener); 

    This method unsubscribes the named ChannelListener from the channel, which means that the listener will receive no new messages. Listeners should be unsubscribed in this manner when they are no longer needed.

  • Get a listing of channel names.

     Enumeration Channel.getChannelNames (); 

    This method returns the names of all channels available on the Message Bus.

  • Subscribe to receive newly added channels.

     Channel.subscribeChannelsUpdate (ChannelsUpdateListener); 

    A ChannelsUpdateListener can subscribe to get updates when channels are added to the Message Bus.

  • Stop receiving newly added channels.

     Channel.unsubscribeChannelsUpdate (ChannelsUpdateListener); 

    A ChannelsUpdateListener can be unsubscribed from channel addition updates. Listeners should be unsubscribed in this manner when they are no longer needed.

  • Add more listeners to a channel.

     textChannel.subscribe (ChannelListener); 

    This method allows the caller to subscribe additional listeners to a channel.

     String textChannel.getName (); 

    This method returns the name of this channel instance.

Interface ChannelListener

The ChannelListener interface must be implemented by any object that wants to be updated when a message comes in on a particular channel.

public interface ChannelListener { public void messageReceived (Channel channel, Object message); } 

In most cases, a client that asks for a Channel instance will subscribe itself to the channel and implement this interface itself, but it isn't necessary. In keeping with JDK 1.1 event adapters, a client can subscribe another object to a channel so that it will consume messages generated by the channel.

In fact, a single listener object can subscribe to multiple channels, which will call the listener's messageReceived() every time a message comes in on any of the channels. The messageReceived () method call provides access to the channel where the message appeared, allowing messageReceived () to separate messages by originating channel.

Interface ChannelsUpdateListener

ChannelsUpdateListener must be implemented by any object that wants to be updated when a channel is added.

public interface ChannelsUpdateListener { public void channelAdded (String name); } 

Class Channel

The Channel class serves two purposes:

  • It provides a simple abstraction as an interface to the client using the Message Bus
  • It maintains global state about available channels and passes messages from channels to the MessageBus implementation and receives updates from the MessageBus implementation

Channel instances are created and stored by Channel's static code. References to them are passed out by Channel.subscribe () as requested by the client. Each Channel instance is unique within the JVM process.

public class Channel {

protected static boolean busSet = false; protected static MessageBus bus; protected static Hashtable channels = new Hashtable (); protected static Vector channelsUpdateListeners = new Vector ();

public static synchronized void setMessageBus (MessageBus mb) throws IOException { if (!busSet) { bus = mb; bus.initBroker (); busSet = true; } else System.out.println ("Can't set MessageBus more than once per runtime!"); }

public static String getBrokerName () { return bus.getBrokerName (); }

public static Enumeration getChannelNames () { return channels.keys (); }

These class methods allow the MessageBus instance to be set once for each runtime, and return information about the bus and channel names, respectively.

 public static synchronized Channel subscribe (String name, ChannelListener cl) throws IOException { Channel ch; if (channels.containsKey (name)) ch = (Channel) channels.get (name); else { bus.addChannel (name); ch = new Channel (name); channels.put (name, ch); } ch.subscribe (cl); return ch; } 

Този метод на клас връща екземпляра на канала, съответстващ на името на канала. Той създава канала и призовава MessageBusда го добави към системата, ако вече не съществува. Веднага след създаването на канала, първоначалният му слушател е регистриран в него.

// извикан от клиенти за регистриране на ChannelsUpdateListener публична статична невалидна subscribeChannelsUpdates (ChannelsUpdateListener cul) {каналиUpdateListeners.addElement (cul); }

// извикан от клиенти за премахване на регистрацията на ChannelsUpdateListener публична статична void unsubscribeChannelsUpdates (ChannelsUpdateListener cul) {каналиUpdateListeners.removeElement (cul); }