Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的RPC实现服务的输出和输入功能,可以和Spring框架无缝集成。
Dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
对于Dubbo框架中,首先要了解其中涉及的三个基本的概念:provider(服务提供方),consumer(服务消费方)和注册中心。接下来,本文从这几个角色的角度,分别实现一个小的demo,以便尽快对于dubbo框架有一个简单的入门。
0、准备
这里们采用的IDE是macOS下的IDEA。我们新健一个名为DubboDemoProj的空Java工程,只选JDK就行,别的都不用选。
我们将在这个工程中,新建各个Module来实现Dubbo框架中的各个角色。
1、接口依赖模块dubbo-api
dubbo-api模块提供统一的接口,最终会打为jar包,供consumer和provider引用。
这里dubbo-api模块新建的时候,要选Maven,但是不要勾选任何archetype,只需要建一个空的Maven项目就行。建好之后,结构如下图。
dubbo-api/pom.xml
是Maven的配置文件。其中,定义了该Module依赖了dubbo框架,同时为了避免Dubbo自带的Spring框架过低,我们排除掉了dubbo自带的spring框架,并显示指定了spring依赖的版本。如下。
4.0.0
com.spacecat.dubbo
dubbo-api
1.0-SNAPSHOT
com.alibaba
dubbo
2.5.3
org.springframework
spring
provided
org.springframework
spring-beans
4.2.5.RELEASE
provided
user-references.xml
文件是该Module的classpath路径下提供了一个xml配置,该配置文件其实就是dubbo消费者的相关配置,后边消费者项目引入api之后可以直接使用该文件。内容如下。
UserService.java
是一个接口,他定义了统一的接口让provider和consumer来引用,内容如下。
package com.dubbo.api;
/**
* Created by chengxia on 2019/5/3.
*/
public interface UserService {
String sayHi(String name);
}
编辑完上述源码文件之后,执行mvn install
命令,将这个module装到mvn的本地仓库。这样,后面的项目就能够通过这个module的坐标在Maven的pom文件中,引用到这个模块。
$ mvn install
[INFO] Scanning for projects...
[INFO]
[INFO] --------------------< com.spacecat.dubbo:dubbo-api >--------------------
[INFO] Building dubbo-api 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ dubbo-api ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 1 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ dubbo-api ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent!
[INFO] Compiling 1 source file to /Users/chengxia/Developer/Java/DubboDemoProj/dubbo-api/target/classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ dubbo-api ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /Users/chengxia/Developer/Java/DubboDemoProj/dubbo-api/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ dubbo-api ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ dubbo-api ---
[INFO] No tests to run.
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ dubbo-api ---
[INFO] Building jar: /Users/chengxia/Developer/Java/DubboDemoProj/dubbo-api/target/dubbo-api-1.0-SNAPSHOT.jar
[INFO]
[INFO] --- maven-install-plugin:2.4:install (default-install) @ dubbo-api ---
[INFO] Installing /Users/chengxia/Developer/Java/DubboDemoProj/dubbo-api/target/dubbo-api-1.0-SNAPSHOT.jar to /Users/chengxia/Developer/Java/tools/apache-maven-3.6.0/repository/com/spacecat/dubbo/dubbo-api/1.0-SNAPSHOT/dubbo-api-1.0-SNAPSHOT.jar
[INFO] Installing /Users/chengxia/Developer/Java/DubboDemoProj/dubbo-api/pom.xml to /Users/chengxia/Developer/Java/tools/apache-maven-3.6.0/repository/com/spacecat/dubbo/dubbo-api/1.0-SNAPSHOT/dubbo-api-1.0-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.537 s
[INFO] Finished at: 2019-05-05T00:45:01+08:00
[INFO] ------------------------------------------------------------------------
ChengdeMacBook-Pro:dubbo-api chengxia$
2、服务提供方模块dubbo-provider
同样是一个在DubboDemoProj中的空Maven模块,建好之后,结构如下图。
pom.xml文件,其中,针对上面dubbo-api模块的依赖,具体如下。
4.0.0
com.spacecat.dubbo
dubbo-provider
1.0-SNAPSHOT
com.alibaba
dubbo
2.5.3
org.springframework
spring
org.springframework
spring-beans
4.2.5.RELEASE
org.springframework
spring-context-support
4.2.5.RELEASE
com.spacecat.dubbo
dubbo-api
1.0-SNAPSHOT
org.apache.zookeeper
zookeeper
3.4.10
com.github.sgroschupf
zkclient
0.1
UserServiceImpl.java
是服务的实现类,如下。
package com.dubbo.provider;
import com.dubbo.api.UserService;
/**
* Created by chengxia on 2019/5/3.
*/
public class UserServiceImpl implements UserService {
public String sayHi(String s) {
return "hello " + s + "!";
}
}
com.dubbo.provider.Main
是启动dubbo服务的,内容如下。
package com.dubbo.provider;
/**
* Created by chengxia on 2019/5/3.
*/
public class Main {
public static void main(String[] args) {
com.alibaba.dubbo.container.Main.main(args);
}
}
这个类调是dubbo框架提供的方法来启动dubbo服务。dubbo会在启动服务时,会读取classpath下一个名为dubbo.properties文件的属性配置。这里我们只要按照dubbo的规则配置相关参数即可,如下:
dubbo.properties
:
dubbo.container=spring
#set dubbo Sping load setting xmls
dubbo.spring.config=classpath:dubbo-provider.xml
dubbo.protocol.name=dubbo
dubbo.protocol.port=28511
dubbo.container指定了dubbo的容器使用spring,dubbo内部有四种容器实现,SpringContainer是其中一种,也是默认的容器。dubbo.spring.config指定了dubbo在启动服务时加载的spring配置文件。dubbo.protocol.name和dubbo.protocol.port分别指定使用的协议名和端口。
上图是Spring源码的截图。SpringContainer类中定义了两个常量,SPRING_CONFIG和DEFAULT_SPRING_CONFIG,大概读一下代码就可以知道,start方法在执行时,会读取dubbo.spring.config属性值,该值指定的就是spring的配置文件,如果没读到,则使用默认的配置。默认配置为classpath*;META-INF/spring/*.xml
,意思是读取classpath下META-INF文件夹下的spring文件夹中的所有xml文件。所以,我们也可以不配置dubbo.spring.config,但是要遵循dubbo默认的读取路径,将spring配置文件放置在META-INF/spring
文件夹下。
dubbo-provider.xml
是一个spring配置文件,只不过引入了dubbo相关的配置:
其中:
-
指定了程序名称,我们可以在dubbo管理后台中通过该名称更清晰的区分服务 -
指定了注册中心的地址,这里用的是本地的zookeeper。 -
指定了集群容错模式,此处为快速失败 -
普通的spring依赖注入 -
服务导出,引用
标签注入的类
3、注册中心
这里的注册中心,我们使用的是zookeeper。
3.1 zookeeper安装
$ brew info zookeeper
zookeeper: stable 3.4.13 (bottled), HEAD
Centralized server for distributed coordination of services
https://zookeeper.apache.org/
Not installed
From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/zookeeper.rb
==> Options
--HEAD
Install HEAD version
==> Caveats
To have launchd start zookeeper now and restart at login:
brew services start zookeeper
Or, if you don't want/need a background service you can just run:
zkServer start
==> Analytics
install: 5,018 (30 days), 14,429 (90 days), 58,577 (365 days)
install_on_request: 1,733 (30 days), 4,463 (90 days), 19,783 (365 days)
build_error: 0 (30 days)
$
执行brew安装命令:
$ brew install zookeeper
Updating Homebrew...
==> Auto-updated Homebrew!
Updated 2 taps (homebrew/core and homebrew/cask).
... ...
==> Deleted Formulae
safe
==> Downloading https://homebrew.bintray.com/bottles/zookeeper-3.4.13.mojave.bottle.tar.gz
==> Downloading from https://akamai.bintray.com/d1/d1e4e7738cd147dceb3d91b32480c20ac5da27d129905f336ba51c0c01b8a476?__gda__=exp=1556685597~hmac=2a06d1cd6581464fdc9510af3179137ee9754a2d28f1fe423eafaebf5fb6aec9&re
######################################################################## 100.0%
==> Pouring zookeeper-3.4.13.mojave.bottle.tar.gz
==> Caveats
To have launchd start zookeeper now and restart at login:
brew services start zookeeper
Or, if you don't want/need a background service you can just run:
zkServer start
==> Summary
/usr/local/Cellar/zookeeper/3.4.13: 244 files, 33.4MB
==> `brew cleanup` has not been run in 30 days, running now...
Removing: /Users/chengxia/Library/Caches/Homebrew/fontconfig--2.13.1.mojave.bottle.tar.gz... (1.2MB)
Removing: /Users/chengxia/Library/Caches/Homebrew/freetype--2.9.1.mojave.bottle.tar.gz... (874.5KB)
Removing: /Users/chengxia/Library/Caches/Homebrew/gd--2.2.5.mojave.bottle.tar.gz... (290KB)
Removing: /Users/chengxia/Library/Caches/Homebrew/jpeg--9c.mojave.bottle.tar.gz... (300.8KB)
Removing: /Users/chengxia/Library/Caches/Homebrew/libtool--2.4.6_1.mojave.bottle.tar.gz... (1003.4KB)
Removing: /Users/chengxia/Library/Logs/Homebrew/tree... (64B)
$
安装后,在/usr/local/etc/zookeeper/目录下,已经有了缺省的配置文件。查看zookeeper配置文件:
$ ls /usr/local/etc/zookeeper
defaults log4j.properties zoo.cfg zoo_sample.cfg
$
缺省配置/usr/local/etc/zookeeper/zoo.cfg
内容如下:
$ cat /usr/local/etc/zookeeper/zoo.cfg
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/usr/local/var/run/zookeeper/data
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1
$
3.2 zookeeper启动
启动zookeeper:
$ zkServer
ZooKeeper JMX enabled by default
Using config: /usr/local/etc/zookeeper/zoo.cfg
Usage: ./zkServer.sh {start|start-foreground|stop|restart|status|upgrade|print-cmd}
ChengdeMacBook-Pro:~ chengxia$ zkServer status
ZooKeeper JMX enabled by default
Using config: /usr/local/etc/zookeeper/zoo.cfg
Error contacting service. It is probably not running.
$ zkServer start
ZooKeeper JMX enabled by default
Using config: /usr/local/etc/zookeeper/zoo.cfg
Starting zookeeper ... STARTED
$ zkServer status
ZooKeeper JMX enabled by default
Using config: /usr/local/etc/zookeeper/zoo.cfg
Mode: standalone
$
3.3 zookeeper简单操作
查看zookeeper的运行状态:
$ zkCli
Connecting to localhost:2181
Welcome to ZooKeeper!
JLine support is enabled
WATCHER::
WatchedEvent state:SyncConnected type:None path:null
[zk: localhost:2181(CONNECTED) 0] ls
[zk: localhost:2181(CONNECTED) 1] ls /
[zookeeper]
[zk: localhost:2181(CONNECTED) 2] ls /zookeeper
[quota]
[zk: localhost:2181(CONNECTED) 3] ls /zookeeper/quota
[]
[zk: localhost:2181(CONNECTED) 4] quit
Quitting...
$
停止运行zookeeper:
$ zkServer stop
ZooKeeper JMX enabled by default
Using config: /usr/local/etc/zookeeper/zoo.cfg
Stopping zookeeper ... STOPPED
$
4、服务消费方
到这里,我们在本地启动zookeeper,然后,在IDEA中运行上面的com.dubbo.provider.Main
,我们就将上面的服务注册到了本机的注册中心(zookeeper)。接下来,可以调用这个服务。
4.1 写一个简单的Spring项目来当做服务消费方
项目结构如下图。
dubbo-consumer/pom.xml
:
4.0.0
com.spacecat.dubbo
dubbo-consumer
1.0-SNAPSHOT
org.springframework
spring-core
4.1.4.RELEASE
org.springframework
spring-context
4.1.4.RELEASE
com.alibaba
dubbo
2.5.3
org.springframework
spring
com.spacecat.dubbo
dubbo-api
1.0-SNAPSHOT
org.apache.zookeeper
zookeeper
3.4.10
com.github.sgroschupf
zkclient
0.1
这个Module中,依赖了dubbo-api。
dubbo-consumer.xml
:
这个文件中,直接引用了dubbo-api模块打包后自带的配置文件user-references.xml
。
com.dubbo.consumer.UserServiceCaller
:
package com.dubbo.consumer;
import com.dubbo.api.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Created by chengxia on 2019/5/5.
*/
public class UserServiceCaller {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("dubbo-consumer.xml");
UserService service = (UserService) context.getBean("userService");
System.out.print("Got service bean:");
System.out.println(service);
System.out.println("RPC call output:");
System.out.println(service.sayHi("Kobe"));
}
}
该文件完成了对服务的调用,可见dubbo框架已经把服务注入到一个本地可以直接调用的bean中了。直接调用bean的方法即可完成对于服务的远程调用(其实,已经和调本地一样了)。
启动zookeeper,运行前面的dubbo-provider模块中的启动类,然后再运行com.dubbo.consumer.UserServiceCaller
,可以得到如下输出。
log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Got service bean:com.alibaba.dubbo.common.bytecode.proxy0@49dc7102
RPC call output:
hello Kobe!
Process finished with exit code 0
4.2 通过命令行调用服务
通过命令行调用服务适用于对dubbo服务做个简单的测试的情况。可以直接在命令行通过telnet的方式来查看和调用dubbo服务。
新版本的MacOS默认没有telnet,可以通过如下步骤安装。
4.2.1 MacOS安装telnet
$ telnet
-bash: telnet: command not found
$ brew install telnet
Updating Homebrew...
==> Auto-updated Homebrew!
Updated 2 taps (homebrew/core and homebrew/cask).
==> New Formulae
pipx
==> Updated Formulae
allureofthestars bluepill dovecot glib-networking gupnp mercurial [email protected] pulumi qt translate-shell
bettercap bzt faas-cli gmic hugo pdftoipe poppler pumba taskell
bit diff-pdf ghq gssdp imagemagick@6 php prototool pushpin tmux
==> Deleted Formulae
node@6
==> Downloading https://homebrew.bintray.com/bottles/telnet-60.mojave.bottle.tar.gz
######################################################################## 100.0%
==> Pouring telnet-60.mojave.bottle.tar.gz
/usr/local/Cellar/telnet/60: 4 files, 138.2KB
ChengdeMacBook-Pro:~ chengxia$ telnet
telnet> quit
$
4.2.2 通过telnet查看和调用dubbo服务。
方法如下示例,这里的端口就是前面dubbo-provider模块中dubbo.properties
文件中配置的端口,这个端口应该就是服务提供方的端口。
$ telnet 127.0.0.1 28511
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
ls
com.dubbo.api.UserService
dubbo>invoke com.dubbo.api.UserService.sayHi("Kobe")
"hello Kobe!"
elapsed: 1 ms.
dubbo>
参考资料
- Mac OSX安装启动 zookeeper
- Dubbo (开源分布式服务框架)
- dubbo入门示例
- 命令行调用远程dubbo服务
- Dubbo入门---搭建一个最简单的Demo框架