写点什么

Dubbo - 初识 Apache Dubbo

用户头像
Java收录阁
关注
发布于: 2020 年 05 月 23 日

为什么要用Dubbo?

随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构越来越流行。和传统的单体架构相比,分布式架构多了一个远程服务之间的通信。无论SOA还是微服务,本质上都是对业务服务的提炼和复用,因此远程服务之间的调用是实现分布式的关键因素。

目前在远程通信这个领域,有很多非常成熟的RPC框架,比如 RMI,WebService,Hessian,Dubbo,Thrift等,即使我们不使用这些RPC框架,我们也可以通过socket或者NIO也可以实现远程通信,那么我们为什么要使用这些现成的RPC框架呢?

原因是因为如果我们自己去开发一个网络通信,需要考虑到下面几点:

  1. 底层网络通信协议的处理

  2. 序列化和反序列化的工作

这些工作本身就是通用的,不应该由业务人员自己来实现,所以才有了RPC框架,使得开发人员不需要关心底层的通信逻辑。

同时,当企业开始大规模的服务化之后,我们还需要考虑以下几点:

  1. 如何实现对服务链路的跟踪和监控

  2. 当服务越来越多时,服务 URL 配置管理变得非常困难,需要服务注册中心来解决服务的发现与感知问题

  3. 要有容错机制防止一个节点故障引发大规模 的系统故障

  4. 负载均衡进行分发请求

对于这些要求,传统的RPC技术就有些力不从心了,所以很多公司就根据需求研发自己的RPC框架,Dubbo就是其中的一个。

dubbo 主要是一个分布式服务治理解决方案,那么什么是服务治理?服务治理主要是针对大规模服务化以后,服务之间的路由、负载均衡、容错机制、 服务降级这些问题的解决方案,而 Dubbo 实现的不仅仅是远程服务通信, 并且还解决了服务路由、负载、降级、容错等功能。

Dubbo的基本使用

我们先通过一个简单的demo来初步了解一下Dubbo的基本用法

创建两个项目dubbo-pratice-service 和dubbo-pratice-client。dubbo-pratice-service这个工程中包含两个子工程,practice-service-api和practice-service-provider。

dubbo-pratice-service这个工程中包含两个子工程,practice-service-api和practice-service-provider,dubbo-practice-service工程作为父工程来管理版本信息,pom.xml文件如下:

dubbo-practice-service的pom文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 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.yrk.dubbo</groupId>
<artifactId>dubbo-practice-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>practice-service-api</module>
<module>practice-service-provider</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.26</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>

通过dependencyManagement来管理项目中依赖的lib的版本。

3. practice-service-api这个工程用来维护所提供服务的api,目录结构如下:





4. practice-service-api的pom文件如下:

<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.yrk.dubbo</groupId>
<artifactId>dubbo-practice-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>practice-service-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>practice-service-api</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

同时在practice-service-api这个工程中定义LoginService接口:

public interface LoginService {
String login(String username, String password);
}

practice-service-provider工程用来提供服务的实现,项目结构如下:

practice-service-provider的pom文件如下:

<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.yrk.dubbo</groupId>
<artifactId>dubbo-practice-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>practice-service-provider</artifactId>
<name>practice-service-provider</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>com.yrk.dubbo</groupId>
<artifactId>practice-service-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

  1. 为LoginService接口提供实现类:

package org.practice.service.provider;
import org.practice.service.api.LoginService;
public class LoginServiceImpl implements LoginService{
public String login(String username, String password) {
if ("admin".equalsIgnoreCase(username) && "admin".equalsIgnoreCase(password)) {
return "Success";
}
return "Failed";
}
}

接下来我们使用xml的形式通过dubbo来发布服务:

我们需要在resources目录下面新建META-INF/spring目录,同时在这个目录下面新建application.xml文件,我们需要在这个文件中定义dubbo相关的信息:





application.xml:

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
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="practice-service" />
<!-- 使用multicast 广播注册中心暴露服务地址 -->
<dubbo:registry address="N/A"/>
<!-- 使用dubbo协议在20880端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20880"/>
<!-- 声明需要暴露的服务接口 -->
<dubbo:service interface="org.practice.service.api.LoginService" ref="loginService"/>
<bean id="loginService" class="org.practice.service.provider.LoginServiceImpl"/>
</beans>

然后通过Main.main(args)来启动服务:

package org.practice.service.provider;
import org.apache.dubbo.container.Main;
public class App
{
public static void main( String[] args )
{
Main.main(args);
}
}

启动服务的时候回在console中看到如下信息

2019-08-15 08:41:38,720 INFO [main] o.a.dubbo.config.AbstractConfig - [DUBBO] Export dubbo service org.practice.service.api.LoginService to local registry url : injvm://127.0.0.1/org.practice.service.api.LoginService?anyhost=true&application=practice-service&bean.name=org.practice.service.api.LoginService&bind.ip=xxxx&bind.port=20880&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.practice.service.api.LoginService&methods=login&pid=11664&register=true&release=2.7.2&side=provider&timestamp=1565829698502, dubbo version: 2.7.2, current host: xxxx
2019-08-15 08:41:38,723 INFO [main] o.a.dubbo.config.AbstractConfig - [DUBBO] Export dubbo service org.practice.service.api.LoginService to url dubbo://xxxx:20880/org.practice.service.api.LoginService?anyhost=true&application=practice-service&bean.name=org.practice.service.api.LoginService&bind.ip=xxxx&bind.port=20880&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.practice.service.api.LoginService&methods=login&pid=11664&register=true&release=2.7.2&side=provider&timestamp=1565829698502, dubbo version: 2.7.2, current host: xxxx

其中dubbo://xxxx:20880/org.practice.service.api.LoginService就是我们我们服务的url。

  1. dubbo-practice-client工程是服务调用的客户端,pom文件如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" 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.yrk.dubbo</groupId>
<artifactId>dubbo-practice-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>dubbo-practice-client</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.26</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>com.yrk.dubbo</groupId>
<artifactId>practice-service-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

在resources目录下创建application.xml文件,内容如下:

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
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="practice-client" />
<dubbo:registry address="N/A"/>
<!-- 通过reference标签获取服务 -->
<dubbo:reference id="loginService" interface="org.practice.service.api.LoginService"
url="dubbo://172.17.23.32:20880/org.practice.service.api.LoginService"/>
</beans>

在Main方法中获取loginService并调用login方法:

public class App
{
public static void main( String[] args )
{
System.out.println( "Hello World!" );
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"application.xml"});
LoginService loginService = (LoginService) context.getBean("loginService");
System.out.println(loginService.login("admin", "admin"));
}
}

运行之后可以在控制台中看到结果:

2019-08-15 10:38:26,811 DEBUG [NettyClientWorker-1-1] i.n.u.ResourceLeakDetectorFactory - Loaded default ResourceLeakDetector: io.netty.util.ResourceLeakDetector@6bf5b77a
2019-08-15 10:38:27,251 DEBUG [DubboClientHandler-172.17.23.32:20880-thread-1] o.a.d.r.transport.DecodeHandler - [DUBBO] Decode decodeable message org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcResult, dubbo version: 2.7.2, current host: 172.17.23.32
Success

表明远程服务调用成功。

关于 Dubbo 启动的真相

通过上面的例子,我们用Dubbo实现了一个非常简单的远程服务调用,同时在上面的例子中,我们并没有使用到tomcat、jetty这类容器,那么Dubbo是如何实现的呢?

其实Dubbo内部提供了几种容器供我们使用去启动和发布服务:

Spring Container: 自动加载META-INF/spring目录下的所有spring配置

logback Container: 自动装配logback日志

Log4j Container: 自动配置log4j的配置

同时Dubbo提供了一个Main.main方法可以快速启动相应的容器,默认情况下只会启动spring容器,Spring容器的类是SpringContainer.java,启动的代码如下:

public static final String SPRING_CONFIG = "dubbo.spring.config";
public static final String DEFAULT_SPRING_CONFIG = "classpath*:META-INF/spring/*.xml";
private static final Logger logger = LoggerFactory.getLogger(SpringContainer.class);
static ClassPathXmlApplicationContext context;
public static ClassPathXmlApplicationContext getContext() {
return context;
}
@Override
public void start() {
String configPath = ConfigUtils.getProperty(SPRING_CONFIG);
if (StringUtils.isEmpty(configPath)) {
configPath = DEFAULT_SPRING_CONFIG;
}
context = new ClassPathXmlApplicationContext(configPath.split("[,\\s]+"), false);
context.refresh();
context.start();
}



发布于: 2020 年 05 月 23 日阅读数: 80
用户头像

Java收录阁

关注

士不可以不弘毅,任重而道远 2020.04.30 加入

喜欢收集整理Java相关技术文档的程序员,欢迎关注同名微信公众号 Java收录 阁获取更多文章

评论

发布
暂无评论
Dubbo - 初识Apache Dubbo