O Apache Dubbo é um framework de serviços de alto desempenho desenvolvido pela Alibaba e atualmente mantido como projeto top-level pelo Apache. Ele oferece capacidades essenciais de comunicação RPC e governança de microserviços. Ao desenvolver microserviços com Dubbo, eles conseguem descobrir e se comunicar remotamente entre si, além de utiilzar as poderosas funcionalidades de governança para implementar soluções como descoberta de serviços, balanceamento de carga e roteamento de tráfego. Este artigo apresenta a integração do Dubbo com o SpringMvc através de configuração via arquivo XML, executando o exemplo básico em um ambiente web. O código fonte estará disponível ao final deste artigo.
Para informações detalhadas sobre Dubbo, visite o site oficial: https://dubbo.apache.org/zh/index.html
1. Configuração do Registro Zookeeper
O diagrama arquitetural oficial do Dubbo mostra que uma aplicação mínima requer três componentes: o registro, provedor de serviço e consumidor de serviço. Não abordaremos monitoramento neste momento, pois o próprio projeto não oferece ferramentas adequadas, mas isso será tratado em um próximo artigo com a instalação do DubboAdmin.
O funcionamento do Dubbo é intuitivo: o provedor registra seus endereços de interface no registro, o consumidor recupera esses endereços e chama os métodos remotos. Quando há mudanças nos endereços, o registro notifica automaticamente o consumidor. Geralmente, provedores e consumidores estão em máquinas distintas, ocultando complexidade da comunicação remota, tornando-a tão simples quento chamadas locais, aumentando significativamente a produtividade no desenvolvimento distribuído.
O registro mais utilizado é o Zookeeper, uma excelente ferramenta de coordenação distribuída. A instalação em Windows é direta. Como tenho limitações de hardware, optei por mostrar a instalação no Windows.
Baixe o Zookeeper no site oficial: https://zookeeper.apache.org/releases.html
Descompacte o pacote baixado (ex: apache-zookeeper-3.7.1-bin.tar.gz). Mude o nome da pasta para "zookeeper" e crie uma subpasta "zkdata" para armazenar dados:
Edite o arquivo zoo.cfg na pasta conf, alterando apenas:
dataDir=D:/Develop/zookeeper/zkdata
clientPort=2181
Execute o script zkServer.cmd na pasta bin para iniciar o servidor.
Para instalar como serviço Windows, utilize o nssm.exe (download: http://www.nssm.cc/download), copie o executável para a pasta bin do Zookeeper e execute:
D:\Develop\zookeeper\bin\nssm.exe install
Preencha os campos solicitados, especificando o caminho completo do zkServer.cmd, diretório de inicialização e nome do serviço (ex: ZookeeperService).
2. Definição de Interface Comum
Este exemplo usa Maven com módulos separados: interface compartilhada, serviço Dubbo e cliente Dubbo.
Na interface compartilhada, defina a interface TestService:
package com.jobs.service;
public interface TestService {
String GetMsg(String name);
int GetCal(int a, int b);
}
3. Servidor Dubbo
O servidor precisa implementar a interface e registrar o serviço no Zookeeper. Para manter o servidor ativo, integre com SpringMvc em um contexto web.
Dependências necessárias:
<dependencies>
<dependency>
<groupId>com.jobs</groupId>
<artifactId>dubbo_interface</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
</dependency>
</dependencies>
Implementação do serviço:
package com.jobs.service.impl;
import com.jobs.service.TestService;
import org.apache.dubbo.config.annotation.Service;
@Service
public class TestServiceImpl implements TestService {
@Override
public String GetMsg(String name) {
return "Hello " + name;
}
@Override
public int GetCal(int a, int b) {
return a + b;
}
}
Arquivo de configuração SpringConfig.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<dubbo:application name="dubbo-service"/>
<dubbo:registry address="zookeeper://localhost:2181"/>
<dubbo:annotation package="com.jobs.service.impl" />
<dubbo:protocol name="dubbo" port="20880"/>
<dubbo:metadata-report address="zookeeper://localhost:2181" />
</beans>
Configuração web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:SpringConfig.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
4. Cliente Dubbo
O cliente conecta-se ao registro, obtém os endereços dos serviços e realiza chamadas. Para testes, integramos ao SpringMvc com endpoints REST.
package com.jobs.controller;
import com.jobs.service.TestService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/test")
public class TestController {
@Reference
private TestService testService;
@RequestMapping("/getmsg")
public String GetMsg(String name) {
return testService.GetMsg(name);
}
@GetMapping("/getcal/{num1}/{num2}")
public int GetCal(@PathVariable("num1") int a, @PathVariable("num2") int b) {
return testService.GetCal(a, b);
}
}
Configuração SpringMvcConfig.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<mvc:annotation-driven/>
<context:component-scan base-package="com.jobs.controller"/>
<dubbo:application name="dubbo-client">
<dubbo:parameter key="qos.port" value="22223"/>
</dubbo:application>
<dubbo:registry address="zookeeper://localhost:2181"/>
<dubbo:annotation package="com.jobs.controller"/>
</beans>
web.xml para cliente:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:SpringMvcConfig.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
Execute primeiro o servidor Dubbo, depois o cliente, e teste acessando os endpoints.
Versões das dependências do projeto pai:
<properties>
<spring.version>5.3.18</spring.version>
<dubbo.version>2.7.4.1</dubbo.version>
<zookeeper.version>4.0.0</zookeeper.version>
<slf4j.version>1.7.21</slf4j.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.jobs</groupId>
<artifactId>dubbo_interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>${zookeeper.version}</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>${zookeeper.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
Download do exemplo: https://files.cnblogs.com/files/blogs/699532/DubboDemo.zip