O Spring fornece suporte para integração de aplicativos em estruturas corporativas usando uma extensão chamada Spring Integration . O objetivo principal é facilitar aplicativos com diversos domínios de negócios; tecnologias trabalham para a interoperabilidade horizontal em toda a empresa. Ele adiciona mensagens leves e integração com sistemas e serviços externos usando uma estrutura de adaptador. Este artigo tem como objetivo fornecer uma compreensão básica da Integração Spring e como ela se estende ao longo do modelo de programação Spring.
Visão geral
Os aplicativos comerciais nada mais são do que soluções para os problemas apresentados pelas unidades de negócios. A magnitude e a complexidade dos problemas determinam se a solução é de escala corporativa ou apenas algumas linhas de código. O problema com o aplicativo corporativo é que, às vezes, uma parte da solução já está disponível usando tecnologias mais antigas que podem não ser rentáveis para reconstruir do zero para combinar com tecnologias mais recentes, seja novo hardware ou software. Este é um problema típico com aplicativos legados. Portanto, o que podemos fazer é criar componentes mais novos que interagem com o sistema existente. Esta é a integração de aplicativos . No entanto, o problema não termina aí. Não é muito fácil criar componentes que funcionem perfeitamente com componentes existentes sem impor restrições desnecessárias à eficiência uns dos outros. Há uma consideração séria que deve ser abordada para a integração perfeita de vários componentes. O Spring Integration considera esses problemas e fornece um ambiente para desenvolvedores codificarem para facilitar a integração. O Spring identifica os padrões comuns envolvidos e faz o trabalho com pouca intervenção dos desenvolvedores.
Acoplamento solto
Como a solução deve usar várias partes, cada parte deve ter preocupações separadas da maneira mais fraca possível. A evolução de um componente não deve representar sérias implicações de projeto e manutenção em outro. Uma situação desacoplada completa não é adequada para integração, nem um acoplamento rígido é aceitável. Portanto, o jogo é projetar o componente da maneira mais fraca possível. Existem algumas maneiras de reduzir o acoplamento em um aplicativo Spring:injeção de dependência ou arquitetura orientada a eventos . Arquitetura orientada a eventos é um termo amplo e tem uma diferença muito tênue entre arquitetura orientada a mensagens, ou MOM. Embora tecnicamente não sejam os mesmos, para este fim, podemos usar os termos de forma intercambiável aqui. Apenas para o bem dos puristas, a diferença básica entre as mensagens orientadas por eventos e orientadas por mensagens é que as mensagens têm destinatários direcionados, enquanto os eventos não são direcionados; caso contrário, sua implementação dificilmente tem uma demarcação clara. Não vamos entrar nisso aqui; em vez disso, vamos nos concentrar em como a arquitetura orientada a eventos é utilizada com o Spring Integration.
Integração Spring orientada a eventos
Na arquitetura orientada a eventos, um aplicativo complexo é dividido em vários componentes de serviço. Esses componentes interagem por meio de eventos gerados por outros componentes, que são chamados de publisher de eventos. Outros componentes que estão interessados nesse evento específico se inscrevem nele e tomam as medidas apropriadas em resposta. Esse é, em essência, o modelo editor-assinante de trabalhar em eventos.
Uma mudança específica no estado é um evento. Conforme declarado, um evento é enviado aos interessados e os assinantes do evento podem optar por responder fornecendo um serviço como executar um processo de negócios, publicar outro evento ou, talvez, ignorá-lo completamente. Isso significa que os eventos, uma vez publicados, não têm qualquer responsabilidade sobre a resposta dos assinantes. Este é um cenário desacoplado e a arquitetura orientada a eventos aproveita esses cenários de acoplamento fraco. O acoplamento solto é particularmente adequado para executar o fluxo de trabalho em tempo real que o Spring Integration requer.
Componentes de integração do Spring
Como uma extensão do framework Spring, o Spring Integration adiciona basicamente três componentes:mensagens, canais de mensagens e terminais. Os desenvolvedores do Spring Integration reconheceram o padrão comum de semelhanças para interoperar entre arquiteturas, domínios e tecnologias variadas na arena corporativa. Portanto, ao introduzir a mensageria por meio de componentes usando pipes e filtro, esse modelo se tornou a base para a integração de aplicativos. Os componentes do filtro consomem ou produzem as mensagens enquanto os pipes, chamados de canais em Spring Integration, descreve o fluxo de mensagens entre filtros.
Há muitos meandros envolvidos. Consulte os links na seção Referências para obter mais detalhes. Aqui, vamos focar em uma implementação simples com DirectChannel .
Um exemplo rápido
O exemplo na Listagem 1 é um aplicativo Spring BOOT que implementa Spring Integration com DirectChannel . Aqui, o canal de mensagem é usado para desacoplar os endpoints do editor e do assinante. O canal de mensagem é usado para estabelecer conexão com os componentes de filtro e adaptador. O exemplo é bem direto e usa DirectChannel com modelos de comunicação editor-assinante e ponto a ponto. Observe que o código é rudimentar e uma implementação simples para ilustrar a ideia do 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>
Listagem 1: pom.xml, dependências do Spring BOOT para uma solução Spring Integration
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; } }
Lista 2: Tweet.java, classe de modelo
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; } }
Listagem 3: TweetPublisher.java, preenche dados de tweets
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()); } }
Listagem 4: Tweeter.java, classe de editor
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"); } }
Listagem 5: TweetReader.java, classe de assinante
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); } }
Listagem 6: SpringIntegrationApplication.java, classe principal do aplicativo
Conclusão
Observe que há muito mais com Spring Integration do que o ilustrado aqui. É apenas a ponta do iceberg. Detalhes importantes são omitidos. Consulte a documentação do Spring para obter mais detalhes sobre isso; links são dados abaixo. Spring Integration tem vantagens, como Inversão de Controle (IoC), programação orientada a aspectos para tratar de preocupações transversais e outras vantagens centrais do Spring Framework à sua disposição. Spring Integration leva mais longe. Os desenvolvedores do Spring Integration não precisam saber como, quando e onde os dados estão. A estrutura trata como a lógica de negócios deve ser executada, manobrando a mensagem por meio de componentes apropriados. Além de um esquema de configuração XML regular, os iniciadores do Spring BOOT fornecem as dependências necessárias para iniciar o código de frente com poucas preocupações sobre dependências.
Referências
- Visão geral da integração do Spring
- Integração do Spring