Olá pessoal!
Neste artigo, demonstraremos os componentes básicos para a criação de microsserviços RESTful usando o registro de serviços Consul, Spring Boot para todos os andaimes, injeção de dependência, Maven para montagem, bem como Spring REST e a API Java RESTful Jersey / JaxRS.
As principais vantagens dos microsserviços:
- Os microsserviços ajudam a afrouxar seu código
- Os microsserviços permitem que diferentes equipes trabalhem em pequenos componentes usando tecnologias independentes, proporcionando uma implantação mais segura e frequente.O Spring Boot suporta várias implementações para criar uma API REST
- A descoberta e a chamada de serviços não dependem da plataforma de serviço
- Swagger cria documentação API robusta e interface de chamada
Se você ainda não está usando microsserviços, não conseguiu entrar na fase dos primeiros seguidores na curva de percepção da tecnologia, e provavelmente é o momento certo para começar.

Nas últimas duas décadas, a empresa se tornou muito flexível em nosso processo SDLC, mas nossos aplicativos, em geral, ainda permanecem monolíticos, com enormes frascos que suportam todas as APIs e versões do mercado. Atualmente, porém, há um desejo por mais processos Lean, DevOps, e a funcionalidade está se tornando "sem servidor". A refatoração para microsserviços pode reduzir o emaranhado de código e recursos, tornar os conjuntos menores, as liberações são mais seguras e as APIs são mais estáveis.
Neste artigo, criaremos um aplicativo simples de gerenciamento de portfólio do mercado de ações que os clientes podem chamar para avaliar seu portfólio de ações (cotações e valores). O microsserviço de portfólio recuperará o portfólio do cliente, o enviará ao microsserviço de preços para aplicar os preços mais recentes e, em seguida, retornará o portfólio totalmente valorizado e subtotalizado, demonstrando tudo isso por meio de uma chamada de descanso.

Antes de começarmos a trabalhar na criação de nossos microsserviços, vamos preparar nosso ambiente configurando o Consul.
Download Consul
Usaremos o Consul Hashicorp para descobrir serviços; acesse
www.consul.io/downloads.html e baixe o Consul para Windows, Linux, Mac, etc. Isso fornecerá um arquivo executável que você precisará adicionar ao seu caminho.
Iniciar Consul
No prompt de comando, iniciando o Consul no modo dev:
consul agent -dev
Para verificar se está em execução, acesse o navegador e acesse a interface do consul
http: // localhost: 8500 . Se tudo correr bem, o cônsul deve informar que está vivo e bem. Ao clicar no serviço de consul (à esquerda), você receberá informações adicionais (à direita).

Se, no momento, houver algum problema, adicione o Consul ao caminho de execução e as portas 8500 e 8600 estarão disponíveis.
Criar um aplicativo SpringBoot
Usaremos o
Spring Initializr , que está integrado na maioria dos IDEs, para montar nossos aplicativos SpringBoot. As capturas de tela abaixo usam o IntelliJ IDEA.
Selecione "Arquivo / Novo projeto" para abrir um novo modelo de projeto e, em seguida, "Spring Initializr".

Em geral, você pode configurar o andaime sem um IDE preenchendo um formulário on-line na página
inicial do SpringBoot Initializr,
start.spring.io , que criará um arquivo zip para o seu projeto vazio, pronto para download.
Clique em "Avançar" e preencha os metadados do projeto. Use a seguinte configuração:

Clique em “Next” para selecionar as dependências e digite “Jersey” e “Consul Discovery” na busca de dependências. Adicione estas dependências:

Clique em “Next” para indicar o nome do projeto e sua localização. Mantenha o nome padrão "portfolio" e especifique o local preferido do projeto, depois clique em "finish" para criar e abrir o projeto:

Podemos usar o application.properties gerado, mas o SpringBoot também reconhece o formato YAML, que é um pouco mais fácil de visualizar, então vamos renomeá-lo para application.yml.
Chamamos o microsserviço de "serviço de portfólio". Podemos especificar uma porta ou usar a porta 0 para que o aplicativo use uma porta disponível. No nosso caso, usaremos 57116. Se você hospedar este serviço como um contêiner do Docker, poderá mapeá-lo para qualquer porta que selecionar. Nomeie o aplicativo e especifique nossa porta adicionando o seguinte ao nosso application.yml:
spring: application: name: portfolio-service server: port: 57116
Para disponibilizar nosso serviço, adicione anotação à nossa classe de aplicativo SpringBoot. Abra o aplicativo PortfolioApplication e adicione @EnableDiscoveryClient acima da declaração da classe.
Confirme as importações. A classe deve ficar assim:
package com.restms.demo.portfolio; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; . . . @SpringBootApplication @EnableDiscoveryClient public class PortfolioApplication { public static void main(String[] args) { SpringApplication.run(PortfolioApplication.class, args); } }
(Para demonstrar como os microsserviços podem consistir em plataformas independentes, usaremos Jersey para este serviço e Spring REST para o próximo).
Para configurar o serviço web RESTful em Jersey, precisamos especificar a classe de configuração ResourceConfig. Adicione a classe JerseyConfig (para demonstração, vamos salvá-la no mesmo pacote da nossa classe de aplicativo). Deve ficar assim, mais o pacote correto e importar:
@Configuration @ApplicationPath("portfolios") public class JerseyConfig extends ResourceConfig { public JerseyConfig() { register(PortfolioImpl.class); } }
Observe que ele herda de ResourceConfig para designá-lo como uma classe de configuração de Jersey. O atributo @ApplicationPath ("portfolios") define o contexto da chamada, o que significa que as chamadas devem começar com o elemento do caminho "portfolioios". (Se você omitir, o contexto padrão é "/").
A classe PortfolioImpl atenderá duas solicitações: portfolios / customer / {customer-id} retorna todos os portfólios e portfolios / customer / {customer-id} / portfolio / {portfolio-id} retorna um portfólio. Uma carteira consiste em um conjunto de tickers e o número de ações detidas por esse ticker. (Para demonstração, existem três clientes com identificadores 0, 1 e 2, cada um dos quais possui três portfólios com identificadores 0, 1 e 2).
Seu IDE solicitará que você crie o PortfolioImpl; faça agora. Para demonstrar, adicione-o ao mesmo pacote. Digite o código abaixo e confirme todas as importações:
@Component @Path("/") public class PortfolioImpl implements InitializingBean { private Object[][][][] clientPortfolios; @GET @Path("customer/{customer-id}") @Produces(MediaType.APPLICATION_JSON) // a portfolio consists of an array of arrays, each containing an array of // stock ticker and associated shares public Object[][][] getPortfolios(@PathParam("customer-id") int customerId) { return clientPortfolios[customerId]; } @GET @Path("customer/{customer-id}/portfolio/{portfolio-id}") @Produces(MediaType.APPLICATION_JSON) public Object[][] getPortfolio(@PathParam("customer-id") int customerId, @PathParam("portfolio-id") int portfolioId) { return getPortfolios(customerId)[portfolioId]; } @Override public void afterPropertiesSet() throws Exception { Object[][][][] clientPortfolios = { { // 3 customers, 3 portfolios each {new Object[]{"JPM", 10201}, new Object[]{"GE", 20400}, new Object[]{"UTX", 38892}}, {new Object[]{"KO", 12449}, new Object[]{"JPM", 23454}, new Object[]{"MRK", 45344}}, {new Object[]{"WMT", 39583}, new Object[]{"DIS", 95867}, new Object[]{"TRV", 384756}}, }, { {new Object[]{"GE", 38475}, new Object[]{"MCD", 12395}, new Object[]{"IBM", 91234}}, {new Object[]{"VZ", 22342}, new Object[]{"AXP", 385432}, new Object[]{"UTX", 23432}}, {new Object[]{"IBM", 18343}, new Object[]{"DIS", 45673}, new Object[]{"AAPL", 23456}}, }, { {new Object[]{"AXP", 34543}, new Object[]{"TRV", 55322}, new Object[]{"NKE", 45642}}, {new Object[]{"CVX", 44332}, new Object[]{"JPM", 12453}, new Object[]{"JNJ", 45433}}, {new Object[]{"MRK", 32346}, new Object[]{"UTX", 46532}, new Object[]{"TRV", 45663}}, } }; this.clientPortfolios = clientPortfolios; } }
A anotação de
componente designa isso como a classe do componente Spring e a expõe como um ponto de extremidade.
As anotações de
caminho sobre a declaração de classe declaram que a classe é acessada através do elemento de caminho "/", e duas chamadas de API suportadas estão disponíveis através de portfolios / customer / {customer-id} e portfolios / customer / {customer-id} / portfolio / {portfolio- id}, como vemos nas anotações do método. Observe que o caminho ("/") é o padrão, mas o deixamos para referência. Os métodos são designados como HTTP GET via @GETannotation. Nosso método é projetado para retornar uma matriz e anotado para retornar Json, portanto, ele retorna uma matriz Json. Observe como as anotações
Path Param são usadas na assinatura do método para extrair os parâmetros exibidos das consultas exibidas.
(Para nossa demonstração, retornamos valores codificados. É claro que, na prática, a implementação consultará o banco de dados ou outro serviço ou fonte de dados em vez do código rígido.)
Agora crie um projeto e execute-o. Se você usar o IntelliJ, ele criará um executável padrão, então basta clicar na seta verde “executar”. Você também pode usar
mvn spring-boot:run
Ou você pode executar a instalação do maven e executar o aplicativo usando java -jar, apontando para o jar gerado no diretório de destino:
java -jar target\portfolio-0.0.1-SNAPSHOT.jar
Agora, devemos ver esse serviço no Consul, então vamos voltar ao nosso navegador, faça o download
http: // localhost: 8500 / ui / # / dc1 / services (ou atualize se você já estiver lá).

Hmm, nós vemos nosso serviço lá, mas ele é exibido como com falha. Isso ocorre porque o Consul espera um sinal de batimento cardíaco "saudável" de nosso serviço.
Para gerar sinais de pulsação, podemos adicionar uma dependência do serviço
Spring Actuator ao pom do nosso aplicativo.
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
Enquanto estamos no pom, observe que há uma versão conflitante com Jersey entre o iniciador do Consul e o iniciador de Jersey. Para facilitar isso, designe o iniciante de Jersey como o primeiro vício.
Seu pom agora deve conter as seguintes dependências:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jersey</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
Ao reiniciar o Consul, o serviço Portfólio exibe um feliz:

Agora, no serviço de portfólio, existem dois nós de transmissão: um deles é a implementação do serviço de portfólio e o outro é a pulsação.
Vamos verificar a porta que foi atribuída. Você pode ver isso na saída do aplicativo:
INFO 19792 --- [ main] sbcetTomcatEmbeddedServletContainer : Tomcat started on port(s): 57116 (http)
Você também pode ver a porta diretamente na interface do usuário do Consul. Clique em “atendimento ao cliente” e selecione o link “Atendimento 'atendimento ao cliente' verificar link”, que exibe a porta de serviço, neste caso 57116.

Solicite
http: // localhost: 57116 / portfolios / customer / 1 / portfolio / 2 e você verá a matriz json [["IBM", 18343], ["DIS", 45673], ["AAPL", 23456]]
Nosso primeiro microsserviço está aberto para negócios!
Serviço de preços
Em seguida, criaremos nosso serviço de preços, desta vez usando o Spring RestController em vez de Jersey.
O serviço de precificação aceitará o identificador do cliente e o identificador do portfólio como parâmetros e usará o RestTemplate para solicitar serviços do portfólio, receber cotações e ações e retornar preços atuais. (Não preciso dizer que esses valores são notícias falsas, portanto, não os use para tomar decisões comerciais!)
Crie um novo projeto usando as seguintes informações:

Desta vez, selecione as dependências da Web, Consul Discovery e Actuator:

Deixe o nome padrão do projeto "pricing" e crie o projeto no diretório de sua escolha.
Desta vez, usaremos application.properties em vez de application.yml.
Defina o nome e a porta em application.properties como:
spring.application.name=pricing server.port=57216
Anote o aplicativo Pricing com @EnableDiscoveryClient. A classe deve ficar assim, mais o pacote e a importação.
@SpringBootApplication @EnableDiscoveryClient public class PricingApplication { public static void main(String[] args) { SpringApplication.run(PricingApplication.class, args); } }
Em seguida, criaremos a classe PricingEndpoint. Aqui darei um exemplo mais detalhado, pois demonstra várias funções importantes, incluindo a descoberta de serviços (pesquisa de serviço de portfólio) e o uso do RestTemplate para consulta:
@RestController @RequestMapping("/pricing") public class PricingEndpoint implements InitializingBean { @Autowired DiscoveryClient client; Map<String, Double> pricingMap = new HashMap<>(); RestTemplate restTemplate = new RestTemplate(); @GetMapping("/customer/{customer-id}/portfolio/{portfolio-id}") public List<String> getPricedPortfolio( @PathVariable("customer-id") Integer customerId, @PathVariable("portfolio-id") Integer portfolioId) { List<ServiceInstance> instances = client.getInstances("portfolio-service"); ServiceInstance instance = instances.stream() .findFirst() .orElseThrow(() -> new RuntimeException("not found")); String url = String.format("%s/portfolios/customer/%d/portfolio/%d", instance.getUri(), customerId, portfolioId); // query for the portfolios, returned as an array of List // of size 2, containing a ticker and a position (
Para encontrar um serviço de portfólio, precisamos ter acesso ao DiscoveryClient. É fácil obter isso com a anotação @Autowired da Spring.
@Autowired DiscoveryClient client;
Essa instância do DiscoveryClient é usada para procurar o serviço na chamada:
List<ServiceInstance> instances = client.getInstances("portfolio-service"); ServiceInstance instance = instances.stream().findFirst().orElseThrow(() -> new RuntimeException("not found"));
Após a localização do serviço, podemos usá-lo para atender a nossa solicitação, que compomos de acordo com a chamada API criada em nosso serviço de portfólio.
String url = String.format("%s/portfolios/customer/%d/portfolio/%d", instance.getUri(), customerId, portfolioId);
Finalmente, usamos RestTemplate para executar nossa solicitação GET.
Object[] portfolio = restTemplate.getForObject(url, Object[].class);
Observe que, para os controladores Rest (e também para o Spring MVC Request Controller), as variáveis de caminho são recuperadas usando a anotação
Path Variable, ao contrário de Jersey, que, como vimos, usa
Path Param.
Isso conclui nossos preços com o Spring RestController.
A documentação
Resolvemos todos esses problemas para criar nossos microsserviços, mas eles não trarão benefícios suficientes se não dermos ao mundo conhecimento sobre como usá-los.
Para fazer isso, usamos a ferramenta
Swagger conveniente e fácil de usar, que não apenas documenta nossas chamadas de API, mas também fornece um cliente Web conveniente para chamá-las.
Primeiro, vamos especificar o Swagger em nosso pom:
<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.7.0</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.7.0</version> </dependency>
Então precisamos dizer ao Swagger quais de nossas aulas queremos documentar. Vamos apresentar a nova classe SwaggerConfig que contém a especificação Swagger.
@Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.any()) .paths(PathSelectors.regex("/pricing.*")) .build(); } }
Vamos ver o que essa classe faz. Primeiro, designamos isso como uma configuração do Swagger com a anotação @ EnableSwagger2.
Em seguida, criamos um componente Docket que informa ao Swagger quais APIs devem ser exibidas. No exemplo acima, pedimos ao Swagger para demonstrar qualquer caminho que comece com "/ pricing". Uma alternativa seria especificar classes para documentação, e não para caminhos:
.apis(RequestHandlerSelectors.basePackage("com.restms.demo")) .paths(PathSelectors.any())
Reinicie o microservice de preço e chame
http: // localhost: 57216 / swagger-ui.html no navegador

Clique em Listar operações para visualizar as operações do serviço em detalhes.
Clique em Expandir operações para criar uma solicitação com base no formulário. Defina alguns parâmetros, clique em "Experimente!" e aguarde a resposta:

Você pode adicionar muito mais cores adicionando anotações do Swagger aos seus métodos.
Por exemplo, decore o método PricingImpl.getPricedPortfolio existente usando a anotação @ApiOperation, como mostrado abaixo:
@ApiOperation(value = "Retrieves a fully priced portfolio", notes = "Retrieves fully priced portfolio given customer id and portfolio id") @GetMapping("/customer/{customer-id}/portfolio/{portfolio-id}") public List<String> getPricedPortfolio(@PathVariable("customer-id") Integer customerId, @PathVariable("portfolio-id") Integer portfolioId)
Recarregue e atualize o swagger-ui para ver a nova documentação atualizada:

E isso não é tudo o que você pode fazer com o Swagger, portanto, verifique a documentação.
Yuri Dvorzhetsky , professor do nosso curso
"Desenvolvedor no Spring Framework", falará mais sobre o trabalho do Spring Boot:
Artigo original