Programmering

Skriv din egen MOM!

MOM misforstås, og MOM får ingen kredit. Du har måske hørt denne før, men i den distribuerede systemarena er det faktisk sandt! Dette skyldes, at meddelelsesorienteret middleware (MOM) traditionelt ikke har haft samme niveau af sofistikering og support som andre teknologier, der anvendes i distribuerede kommunikationsrammer.

Men tiderne ændrer sig. Med introduktionen af ​​sofistikerede, robuste leverandørtilbud vokser interessen for MOM-systemer hurtigt. Gode ​​MOM-implementeringer leverer en applikationsgrænseflade på højt niveau, servicekvalitetsgarantier og et væld af tjenester såsom sikkerhed, meddelelseskø og katalogstøtte, der er nødvendige for "industriel styrke" distribueret kommunikation.

Distribuerede kommunikationsrammer

Formålet med en distribueret kommunikationsramme er at give en god måde, hvorpå delene af et distribueret system kan kommunikere. Objektorienterede rammer udfører denne opgave ved at give distribuerede objekter en måde at kommunikere hinanden på.

De distribuerede objektorienterede rammer, der får mest opmærksomhed, er dem, der modellerer beskeder som metodeopkald. CORBA og RMI er to fremragende eksempler på denne type rammer (se Ressourcer). Disse systemer kaldes ofte RPC-systemer (Remote Procedure Call). Magien ved disse systemer er, at de foretager fjernprocedure (eller metode) opkald ser ud til at være lokale procedurekald (LPC'er).

RPC'er arkiveres på klient / server mønster. For eksempel kaldes CORBA-objekter, der udsætter metoder, der skal kaldes af eksterne objekter, servere (og er).

Introduktion til MOM

I modsætning til RPC'er modellerer MOM'er ikke meddelelser som metodeopkald; i stedet modellerer de dem som begivenheder i et leveringssystem for begivenheder. Kunder sender og modtager begivenheder eller "meddelelser" via API'er, som MOM leverer. MOM kan præsentere katalogtjenester, der lader klienter slå op i et andet program, der fungerer som en server, eller det kan præsentere alsidige "kanaler", der lader en gruppe klienter kommunikere som jævnaldrende, eller den kan præsentere begge muligheder.

Alle applikationer kommunikerer direkte med hinanden ved hjælp af MOM. Beskeder genereret af applikationer er kun meningsfulde for andre klienter, fordi MOM i sig selv kun er en beskedrouter (og i nogle tilfælde også et system til kø-beskeder).

MOMS kommer i alle former og størrelser

Alle MOM'er har to grundlæggende karakteristika: de muliggør videregivelse af meddelelser og videregivelse af beskeder er ikke-blokerende. Ud over disse grundlæggende kan leverandører implementere et hvilket som helst antal forskellige grænseflader og tjenester.

Mange MOM'er har en udgivelses- og abonnementsgrænseflade, der gør det muligt for applikationer at udgive og modtage meddelelser, som de er interesserede i. Denne grænseflade kan have form af et kanalbaseret system eller et mere simpelt system, hvor en klient registrerer typer af meddelelser. det er interesseret i at modtage.

Grundlæggende MOM'er leverer kun direkte beskeder, ingen yderligere tjenester. Avancerede MOM'er giver beskedkø og garanteret levering sammen med sikkerhed, dataovervågning på tværs af platforme, skalerbarhed og andre fordele.

MOMS et overblik

Her er en hurtig reference, der hjælper dig med at få styr på, hvad MOMS handler om.

MOM fordele

  • Enkel: Kunder udgiver og abonnerer

    publish-and-subscribe er en nyttig abstraktion på højt niveau for, hvad apps skal gøre for at kommunikere.

  • Let: Ingen kompliceret opsætning påkrævet

    MOM'er er nemme at installere og bruge, i modsætning til komplekse RPC-baserede systemer som CORBA.

  • Generisk: Den samme MOM kan bruges til flere apps

    Da ethvert MOM-system i det væsentlige kun er en generisk meddelelsestransport, kan det genbruges i forskellige applikationer uden yderligere arbejde.

  • Fleksibel: Enhver form for besked kan sendes

    Enhver besked kan sendes af MOM. Fordi MOM ikke forstår meddelelserne, betyder det ikke noget, hvad de er.

MOM ulemper

  • Generisk: Applikationer skal forstå meddelelser

    At få applikationer til at bruge beskeder i stedet for metodeopkald kan være vanskelig, især hvis applikationen er afhængig af, at metoden kalder blok.

  • Ukendt: Modellerer ikke metodeopkald

    Udviklere, der ikke kender beskeder, kan have problemer med at finde ud af, hvordan de kan bruges effektivt.

  • Asynkron: Beskeder blokeres ikke

    Beskeder er naturligvis ikke-blokering. Dette gør det sværere at skrive apps, der har brug for blokering af opkald.

  • For simpelt: Ingen datakørsel

    Selv enkle RPC-systemer samler data korrekt. Enkle MOMS kan bare sende meddelelser, hvor byte er ude af drift fra modtagerens synspunkt.

  • Ikke standard: Leverandører er overalt

    Implementeringer af leverandør-MOM gør alt ... og intet.

    Advarsel Emptor

    er den sætning, du skal huske på, når du gennemgår de forskellige leverandørtilbud.

Hvornår er MOM'er passende?

  • Ved kommunikation skal apps bruge beskeder
  • Når programmeringspersonale ikke er bundet til klient / server og RPC-systemer
  • Når CORBA / RMI og relaterede systemer er for komplekse
  • Når enkle RPC-systemer er for rudimentære

Designhensyn til vores MOM

Nu hvor baggrunden er ude af vejen, lad os begynde at sammensætte vores MOM, den Beskedbus. Vi bruger MOM til at muliggøre kommunikation mellem distribuerede whiteboard-klienter. (Se Ressourcer for links til oplysninger om whiteboard-applikationen, vi har arbejdet med i de sidste par rater.)

Den drivende overvejelse for Message Bus er, at den giver en praktisk kommunikationsgrænseflade på højt niveau til de applikationsobjekter, der vil bruge den.

Fordi en kanal giver mening som den centrale tjeneste, som Message Bus skal levere, er grænsefladen til Message Bus den Kanal klasse. Klienten bruger Kanal klasse for at få adgang til alle funktioner på højt niveau i Message Bus, fra abonnement og udgivelse til liste over tilgængelige kanaler i systemet.

Det Kanal klasse afslører klassemetoder, der påvirker Message Bus som helhed eller vedrører alle kanaler. Hver kanalforekomst repræsenterer en enkelt kanal i systemet og udsætter kanalspecifikke metoder.

To grænseflader, ChannelListener og ChannelsUpdateListener, tilvejebringes med det formål at abonnere på modtagelse af meddelelser på en kanal henholdsvis modtagelse af underretning om kanaltilføjelse.

Billedet nedenfor illustrerer Message Bus-systemarkitekturen.

Under kølerhjelmen

Under hætten bruger Message Bus-applikationen klassemetoder og datastrukturer af

Kanal

for at holde styr på kanaler. Lyttere til en kanal implementerer

ChannelListener

interface og objekter, der ønsker at modtage opdateringer om kanal tilføjer implementere

ChannelsUpdateListener

interface. Registrerede lytteobjekter kaldes tilbage af

Kanal

når der sker noget interessant. Al kommunikation med omverdenen sker med en transportspecifik implementering af

MessageBus

interface, f.eks

MessageBusSocketImpl

.

Hver MessageBus implementering sender meddelelser ved at tale med en tilsvarende meddelelsesoverførende server, kaldet en mægler, over en delt netværkstransport, såsom sockets eller URL / servlets. Mægleren ruter beskeder blandt MessageBus forekomster, der hver svarer til en Kanal klasse.

Fordi disse transportspecifikke implementeringer alle implementerer MessageBus interface er de udskiftelige. For eksempel en servletbaseret MessageBus og mægler kan bruges af Kanal i stedet for stikkontakterne MessageBus og mægler.

Vores Message Bus er et simpelt peer-to-peer-system baseret på kanaler, hvilket gør det velegnet til brug i et peer-to-peer-program, såsom et samarbejdssystem.

Brug af Message Bus i et klientprogram

Disse trin giver en klient mulighed for at bruge Message Bus:

  1. Opret en forekomst af MessageBus.

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

    I dette opkald, en ny MessageBus implementering oprettes, med mægleren identificeret ved argumenterne til konstruktøropkaldet.

  2. Abonner på en kanal.

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

    Dette opkald returnerer en forekomst af kanalen, der svarer til kanalnavnargumentet. Hvis kanalen ikke findes, oprettes den i systemet.

    Aflevering det her som argument betyder, at den, der ringer op, selv er a ChannelListener. Den, der ringer op, kan abonnere ikke kun på sig selv, men også på enhver ChannelListener til kanalen eller et vilkårligt antal lyttere til en enkelt kanal.

  3. Offentliggør en besked til kanalen.

     textChannel.publish (ny streng (myID + "siger Hej!")); 

    Det er let at offentliggøre en besked og medfører intet andet end at ringe offentliggøre() på den valgte kanalinstans. Bemærk, at meddelelsen kan være en hvilken som helst type objekt, så længe andre klienter på kanalen kan forstå den, og serveren har adgang til beskedklassefil (erne) (som beskrevet i afsnittet Brug af beskedbussen)

Yderligere valgfri trin inkluderer:

  • Afmeld en lytter fra en kanal.

     textChannel.unsubscribe (ChannelListener); 

    Denne metode afslutter det navngivne ChannelListener fra kanalen, hvilket betyder, at lytteren ikke modtager nye beskeder. Lyttere skal afmelde sig på denne måde, når de ikke længere er nødvendige.

  • Få en liste over kanalnavne.

     Enumeration Channel.getChannelNames (); 

    Denne metode returnerer navnene på alle tilgængelige kanaler i Message Bus.

  • Abonner for at modtage nyligt tilføjede kanaler.

     Channel.subscribeChannelsUpdate (ChannelsUpdateListener); 

    EN ChannelsUpdateListener kan abonnere for at få opdateringer, når kanaler føjes til Message Bus.

  • Stop med at modtage nyligt tilføjede kanaler.

     Channel.unsubscribeChannelsUpdate (ChannelsUpdateListener); 

    EN ChannelsUpdateListener kan afmeldes fra opdateringer til tilføjelse af kanaler. Lyttere skal afmelde sig på denne måde, når de ikke længere er nødvendige.

  • Føj flere lyttere til en kanal.

     textChannel.subscribe (ChannelListener); 

    Denne metode gør det muligt for den, der ringer op, at abonnere yderligere lyttere på en kanal.

     String textChannel.getName (); 

    Denne metode returnerer navnet på denne kanalforekomst.

Interface ChannelListener

Det ChannelListener interface skal implementeres af ethvert objekt, der ønsker at blive opdateret, når en besked kommer ind på en bestemt kanal.

offentlig grænseflade ChannelListener {public void messageReceived (Channel channel, Object message); } 

I de fleste tilfælde er en klient, der beder om en Kanal instans abonnerer sig selv på kanalen og implementerer selv denne grænseflade, men det er ikke nødvendigt. I overensstemmelse med JDK 1.1-hændelsesadaptere kan en klient abonnere på et andet objekt på en kanal, så den vil forbruge meddelelser genereret af kanalen.

Faktisk kan et enkelt lytterobjekt abonnere på flere kanaler, som kalder lytteren messageReceived () hver gang der kommer en besked på en af ​​kanalerne. Det messageReceived () metodeopkald giver adgang til den kanal, hvor meddelelsen dukkede op, hvilket tillader messageReceived () for at adskille meddelelser med oprindelig kanal.

Interface ChannelsUpdateListener

ChannelsUpdateListener skal implementeres af ethvert objekt, der ønsker at blive opdateret, når en kanal tilføjes.

offentlig grænseflade ChannelsUpdateListener {public void channelAdded (String name); } 

Klasse Kanal

Det Kanal klasse tjener to formål:

  • Det giver en simpel abstraktion som grænseflade til klienten ved hjælp af Message Bus
  • Det opretholder en global tilstand om tilgængelige kanaler og sender meddelelser fra kanaler til MessageBus implementering og modtager opdateringer fra MessageBus implementering

Kanal forekomster oprettes og gemmes af Kanals statiske kode. Henvisninger til dem videregives af Channel.subscribe () som anmodet af klienten. Hver Kanal forekomst er unik inden for JVM-processen.

offentlig klassekanal {

beskyttet statisk boolsk busSet = falsk; beskyttet statisk MessageBus-bus; beskyttede statiske Hashtable-kanaler = ny Hashtable (); beskyttede statiske vektorkanalerUpdateListeners = ny vektor ();

offentligt statisk synkroniseret ugyldigt setMessageBus (MessageBus mb) kaster IOException {if (! busSet) {bus = mb; bus.initBroker (); busSet = sandt; } ellers System.out.println ("Kan ikke indstille MessageBus mere end én gang pr. kørselstid!"); }

offentlig statisk streng getBrokerName () {retur bus.getBrokerName (); }

offentlig statisk optælling getChannelNames () {return channels.keys (); }

Disse klassemetoder tillader MessageBus instans, der skal indstilles en gang for hver runtime, og returnere oplysninger om henholdsvis bus- og kanalnavne.

 offentlig statisk synkroniseret kanalabonnement (strengnavn, ChannelListener cl) kaster IOException {Channel ch; hvis (channel.containsKey (navn)) ch = (Channel) kanaler.get (navn); ellers {bus.addChannel (navn); ch = ny kanal (navn); channel.put (navn, ch); } ch.subscribe (cl); returnere ch; } 

Denne klassemetode returnerer kanalinstansen svarende til kanalnavnet. Det skaber kanalen og opkaldene MessageBus at tilføje det til systemet, hvis det ikke allerede findes. Så snart kanalen oprettes, er dens oprindelige lytter registreret hos den.

// kaldes af klienter til at registrere ChannelsUpdateListener offentlig statisk ugyldig subscribeChannelsUpdates (ChannelsUpdateListener cul) {kanalerUpdateListeners.addElement (cul); }

// kaldes af klienter til at afregistrere ChannelsUpdateListener public static void unsubscribeChannelsUpdates (ChannelsUpdateListener cul) {kanalerUpdateListeners.removeElement (cul); }