Spring giver support til applikationsintegration på tværs af virksomhedsrammer ved at bruge en udvidelse kaldet Spring Integration . Det primære mål er at facilitere applikationer med forskellige forretningsdomæner; teknologier arbejder hen imod horisontal interoperabilitet på tværs af virksomheden. Den tilføjer letvægtsmeddelelser og integration med eksterne systemer og tjenester ved hjælp af en adapterramme. Denne artikel har til formål at give en grundlæggende forståelse af Spring Integration og hvordan den strækker sig over Spring-programmeringsmodellen.
Oversigt
Kommercielle applikationer er intet andet end løsninger på problemer fra forretningsenheder. Størrelsen og kompleksiteten af problemerne afgør, om løsningen er af virksomhedsskala eller blot nogle få linjer kode. Problemet med virksomhedsapplikationen er, at nogle gange er en del af løsningen allerede tilgængelig ved brug af ældre teknologier, som måske ikke er omkostningseffektive at genopbygge fra bunden for at matche nyere teknologier, hvad enten det er ny hardware eller software. Dette er et typisk problem med ældre applikationer. Derfor er det, vi kan gøre, at skabe nyere komponenter, der fungerer sammen med det eksisterende system. Dette er applikationsintegration . Problemet slutter dog ikke der. Det er ikke særlig let at skabe komponenter, der fungerer problemfrit med eksisterende komponenter uden at pålægge unødvendige begrænsninger for hinandens effektivitet. Der er en alvorlig overvejelse, der skal tages op for problemfri integration af flere komponenter. Spring Integration overvejer disse problemer og giver et miljø for udviklere at kode for nem integration. Spring identificerer de almindelige involverede mønstre og udfører arbejdet med små udvikleres indgriben.
Løs kobling
Fordi løsningen skal bruge flere dele, skal hver del have separate bekymringer på en så løst koblet måde som muligt. Udviklingen af en komponent må ikke medføre alvorlige design- og vedligeholdelsesimplikationer for en anden. En fuldstændig afkoblet situation er ikke egnet til integration, og en tæt kobling er heller ikke acceptabel. Derfor er spillet at designe komponenten på en måde så løst koblet som muligt. Der er et par måder at reducere kobling på i en Spring-applikation:afhængighedsinjektion eller hændelsesdrevet arkitektur . Hændelsesdrevet arkitektur er et bredt begreb og har en meget fin forskel mellem meddelelsesdrevet arkitektur eller MOM. Selvom de teknisk set ikke er de samme, kan vi til dette formål bruge vilkårene i flæng her. Blot for puristens skyld er den grundlæggende forskel mellem begivenhedsdrevet og beskeddrevet, at beskeder har dirigeret modtagere, hvorimod begivenheder er urettede; ellers har deres gennemførelse næppe en klar afgrænsning. Lad os ikke komme ind på det her; lad os i stedet fokusere på, hvordan begivenhedsdrevet arkitektur bruges med Spring Integration.
Hændelsesdrevet fjederintegration
I begivenhedsdrevet arkitektur er en kompleks applikation opdelt i flere servicekomponenter. Disse komponenter interagerer via hændelser genereret af andre komponenter, som kaldes udgiveren af begivenheder. Andre komponenter, der er interesserede i den pågældende begivenhed, abonnerer på den og træffer passende foranstaltninger som reaktion. Dette er i bund og grund udgiver-abonnentmodellen for at arbejde med begivenheder.
En specifik tilstandsændring er en begivenhed. Som nævnt en begivenhed sendes til interesserede, og event-abonnenterne kan vælge at svare ved at levere en service såsom at eksekvere en forretningsproces, udgive en anden begivenhed eller måske helt ignorere den. Det betyder, at begivenhederne, når de først er offentliggjort, ikke har noget ansvar for abonnenternes svar. Dette er et afkoblet scenarie, og begivenhedsdrevet arkitektur udnytter sådanne løse koblingsscenarier. Løs kobling er særligt velegnet til at udføre arbejdsflow i realtid, som Spring Integration kræver.
Fjederintegrationskomponenter
Som en udvidelse af Spring-rammen tilføjer Spring Integration grundlæggende tre komponenter:beskeder, beskedkanaler og slutpunkter. Spring Integration-udviklere anerkendte det fælles mønster af ligheder for at interoperere mellem forskellige arkitekturer, domæner og teknologier i virksomhedsarenaen. Derfor blev denne model grundlaget for applikationsintegration ved at introducere beskeder gennem komponent ved hjælp af rør og filter. Filterkomponenterne forbruger eller producerer meddelelserne, mens rørene, kaldet kanaler i Spring Integration, beskriver meddelelsesflowet mellem filtre.
Der er mange forviklinger involveret. Se linkene i afsnittet Referencer for flere detaljer. Lad os her i stedet fokusere på en simpel implementering med DirectChannel .
Et hurtigt eksempel
Eksemplet i liste 1 er en Spring BOOT-applikation, som implementerer Spring Integration med DirectChannel . Her bruges beskedkanalen til at afkoble udgiver- og abonnentendepunkter. Meddelelseskanalen bruges til at etablere forbindelse med filter- og adapterkomponenterne. Eksemplet er ret ligetil og bruger DirectChannel med udgiver-abonnent og punkt-til-punkt kommunikationsmodeller. Bemærk, at koden er rudimentær og en enkel implementering for at illustrere ideen om Spring Integration.
<?xml version="1.0" encoding="UTF-8"?> <project xmlns_xsi="http://www.w3.org/2001/XMLSchema-instance" xsi_schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mano.example</groupId> <artifactId>spring-integration</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>spring-integration</name> <description>Demo project for Spring BOOT</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.6.RELEASE</version> <relativePath/> <!-- look up parent from repository --> </parent> <properties> <project.build.sourceEncoding> UTF-8 </project.build.sourceEncoding> <project.reporting.outputEncoding> UTF-8 </project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId> spring-boot-starter-integration </artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId> spring-boot-starter-test </artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId> org.springframework.boot </groupId> <artifactId> spring-boot-maven-plugin </artifactId> </plugin> </plugins> </build> </project>
Fortegnelse 1: pom.xml, Spring BOOT-afhængigheder for en Spring-integrationsløsning
package com.mano.example.springintegration.model; import java.util.Date; public class Tweet { private long tid; private String text; private Date time; private String hashTag; @Override public String toString() { return "Tweet{" + "tid=" + tid + ", text='" + text + ''' + ", time=" + time + ", hashTag='" + hashTag + ''' + '}'; } public long getTid() { return tid; } public void setTid(long tid) { this.tid = tid; } public String getText() { return text; } public void setText(String text) { this.text = text; } public Date getTime() { return time; } public void setTime(Date time) { this.time = time; } public String getUser() { return hashTag; } public void setUser(String hashTag) { this.hashTag = hashTag; } }
Fortegnelse 2: Tweet.java, modelklasse
package com.mano.example.springintegration.repo; import com.mano.example.springintegration.model.Tweet; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.Date; import java.util.List; @Component public class TweetPublisher { private static long id; public List<Tweet> getTweets(){ List<Tweet> tweets = new ArrayList<>(); tweets.add(createTweet("Storms in Pacific","#weather")); tweets.add(createTweet("what's up developers?","#dev")); tweets.add(createTweet("Chinese delicacy in Amazon", "#traveller")); tweets.add(createTweet("inflation down by 2%","#stock")); tweets.add(createTweet("save river","#environment")); tweets.add(createTweet("New star found","#astronaut")); tweets.add(createTweet("Learn math quickly","#tutor")); tweets.add(createTweet("Save animals","#bovine")); tweets.add(createTweet("stars are favorable now", "#astro")); tweets.add(createTweet("social unrest in the world", "#concern")); return tweets; } Tweet createTweet(String text, String hashTag){ Tweet tweet = new Tweet(); tweet.setTid(id++); tweet.setUser(hashTag); tweet.setText(text); tweet.setTime(new Date()); return tweet; } }
Fortegnelse 3: TweetPublisher.java, udfylder tweetdata
package com.mano.example.springintegration.pub; import com.mano.example.springintegration.model.Tweet; import org.springframework.beans.factory.annotation.Value; import org.springframework.integration.channel.DirectChannel; import org.springframework.integration.support .MessageBuilder; import org.springframework.stereotype.Component; @Component public class Tweeter { private DirectChannel channel; @Value("#{tweetChannel}") public void setChannel(DirectChannel channel) { this.channel = channel; } public void sendTweetReaders(Tweet tweet) { System.out.println("New Tweet - " + tweet.toString()); channel.send(MessageBuilder.withPayload(tweet) .build()); } }
Fortegnelse 4: Tweeter.java, udgiverklasse
package com.mano.example.springintegration.sub; import com.mano.example.springintegration.model.Tweet; import org.springframework.integration .MessageRejectedException; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHandler; import org.springframework.messaging.MessagingException; import org.springframework.stereotype.Component; @Component public class TweetReader implements MessageHandler { @Override public void handleMessage(Message<?> message) throws MessagingException { Object payload = message.getPayload(); if (payload instanceof Tweet) { receiveAndAcknowledge((Tweet) payload); } else { throw new MessageRejectedException(message, "Unknown data type has been received."); } } void receiveAndAcknowledge(Tweet tweet) { System.out.println("Hi Tweeter, this is Reader #" + System.identityHashCode(this) + "." + "Received tweet - " + tweet.toString() + "n"); } }
Fortegnelse 5: TweetReader.java, abonnentklasse
package com.mano.example.springintegration; import com.mano.example.springintegration.incoming .TweetPublisher; import com.mano.example.springintegration.model.Tweet; import com.mano.example.springintegration.pub.Tweeter; import com.mano.example.springintegration.sub.TweetReader; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure .SpringBootApplication; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.integration.channel.DirectChannel; import org.springframework.messaging.MessageChannel; import java.util.List; @SpringBootApplication @ComponentScan(basePackages = "com.mano.example.springintegration") public class SpringIntegrationApplication { @Autowired private TweetPublisher tweetPublisher; @Autowired private Tweeter tweeter; @Autowired private DirectChannel channel; @Bean public MessageChannel tweetChannel(){ return new DirectChannel(); } @Bean public CommandLineRunner commandLineRunner (ApplicationContext context){ return args -> { channel.subscribe(new TweetReader()); channel.subscribe(new TweetReader()); channel.subscribe(new TweetReader()); List<Tweet> tweets = tweetPublisher.getTweets(); for (Tweet tweet: tweets){ tweeter.sendTweetReaders(tweet); } }; } public static void main(String[] args) { SpringApplication.run(SpringIntegrationApplication .class, args); } }
Fortegnelse 6: SpringIntegrationApplication.java, hovedapplikationsklasse
Konklusion
Bemærk, at der er meget mere med Spring Integration end vist her. Det er kun toppen af isbjerget. Vigtige detaljer er udeladt. Se forårets dokumentation for flere detaljer om dette; links er givet nedenfor. Spring Integration har fordele, såsom Inversion of Control (IoC), aspektorienteret programmering til at løse tværgående bekymringer og andre kernefordele ved Spring Framework til sin rådighed. Spring Integration tager det videre. Udviklere af Spring Integration behøver ikke at vide om, hvordan, hvornår og hvor dataene befinder sig. Rammen håndterer, hvordan forretningslogikken skal udføres ved at manøvrere budskabet gennem passende komponenter. Bortset fra en almindelig XML-konfigurationsordning, leverer Spring BOOT startere de nødvendige afhængigheder til at starte kode direkte med små bekymringer om afhængigheder.
Referencer
- Oversigt over forårets integration
- Forårsintegration