Dubbo - 初识Apache Dubbo

为什么要用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的基本用法

  1. 创建两个项目dubbo-pratice-service 和dubbo-pratice-client。dubbo-pratice-service这个工程中包含两个子工程,practice-service-api和practice-service-provider。
    在这里插入图片描述
  2. 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);
}
  1. practice-service-provider工程用来提供服务的实现,项目结构如下:
    在这里插入图片描述
  2. 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();
    }

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无法无天过路客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值