作为一个php程序员转java开发,一直停留在 hello world 的水平上,最近由于一时发热想试一下 dubbo 的新版本,但是 github 找了一遍又一遍都没有看到有demo,而官方给出的例子复制出来是没办法单独运行的,不是这个错就那个错,反正搞了一下午也没有解决。
于是决定自己试一试,填补一下搜索引擎空白。
废话少说,show me the code !
现在开始用 IDEA 创建一个没有代码的 Spring boot maven 工程
选择 Spring Initializr 初始化项目
创建 api 模块,即 interface 定义
创建 service 模块,即 provider 服务提供者
创建 web 模块,即 consumer 服务消费者
创建完这个模块之后来执行个 mvn clean install 试一下,结果报错了
[INFO] skip non existing resourceDirectory /Users/jeftom/workspace/java/dubbo-sample/dubbo-demo/src/main/resources [INFO] [INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ dubbo-demo --- [INFO] No sources to compile [INFO] [INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ dubbo-demo --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] skip non existing resourceDirectory /Users/jeftom/workspace/java/dubbo-sample/dubbo-demo/src/test/resources [INFO] [INFO] --- maven-compiler-plugin:3.8.0:testCompile (default-testCompile) @ dubbo-demo --- [INFO] No sources to compile [INFO] [INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ dubbo-demo --- [INFO] No tests to run. [INFO] [INFO] --- maven-jar-plugin:3.1.1:jar (default-jar) @ dubbo-demo --- [WARNING] JAR will be empty - no content was marked for inclusion! [INFO] Building jar: /Users/jeftom/workspace/java/dubbo-sample/dubbo-demo/target/dubbo-demo-0.0.1-SNAPSHOT.jar [INFO] [INFO] --- spring-boot-maven-plugin:2.1.3.RELEASE:repackage (repackage) @ dubbo-demo --- [INFO] ------------------------------------------------------------------------ [INFO] BUILD FAILURE [INFO] ------------------------------------------------------------------------ [INFO] Total time: 3.142 s [INFO] Finished at: 2019-03-23T22:05:17+08:00 [INFO] Final Memory: 24M/395M [INFO] ------------------------------------------------------------------------ [ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.1.3.RELEASE:repackage (repackage) on project dubbo-demo: Execution repackage of goal org.springframework.boot:spring-boot-maven-plugin:2.1.3.RELEASE:repackage failed: Unable to find main class -> [Help 1] [ERROR] [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch. [ERROR] Re-run Maven using the -X switch to enable full debug logging. [ERROR] [ERROR] For more information about the errors and possible solutions, please read the following articles: [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginExecutionException 复制代码
找到 Tests 单元测试用例,加上 @Ignore 注释跳转先,剩下的先不管那么多了。
在根模块的 pom.xml 里增加
<packaging>pom</packaging> <modules> <module>dubbo-demo-api</module> <module>dubbo-demo-service</module> <module>dubbo-demo-web</module> </modules> 复制代码
打包插件也需要调整一下,因为根模板没有使用到 spring boot 的 main 启动类,换成 maven 的打包插件才能继续下去。
<build> <pluginManagement> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> <plugin> <artifactId>maven-site-plugin</artifactId> <version>3.7.1</version> </plugin> <plugin> <artifactId>maven-project-info-reports-plugin</artifactId> <version>3.0.0</version> </plugin> </plugins> </pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-site-plugin</artifactId> <configuration> <locales>en,fr</locales> </configuration> </plugin> </plugins> <!-- 这里要把 spring boot 自带的 spring-boot-maven-plugin 插件换成 maven-site-plugin,否则 mvn 打包会报错 --> <!-- <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> --> </build> 复制代码
在其它三个子模块的 pom.xml 增加
<packaging>jar</packaging> 复制代码
修改完成之后,执行 mvn clean install 试一下
[INFO] ------------------------------------------------------------------------ [INFO] Reactor Summary: [INFO] [INFO] dubbo-demo-api ..................................... SUCCESS [ 5.428 s] [INFO] dubbo-demo-service ................................. SUCCESS [ 1.299 s] [INFO] dubbo-demo-web ..................................... SUCCESS [ 3.195 s] [INFO] dubbo-demo ......................................... SUCCESS [ 0.039 s] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 11.258 s [INFO] Finished at: 2019-03-23T22:21:46+08:00 [INFO] Final Memory: 50M/525M [INFO] ------------------------------------------------------------------------ 复制代码
离成功又近了一步,虽然还没有任何代码,但是起码几个模块已经 build 通过了。
删除 dubbo-demo-api 里的启动类,因为这个模块主要保存的是接口的定义。
增加 DemoApi 接口类
package com.example.dubbo.demo.api; /** * Demo 接口定义 * * @author jeftom * @date 2019-03-23 22:35 * @since 1.0.0 */ public interface DemoApi { String sayHello(String name); } 复制代码
pom 文件打包插件改为:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> </plugin> </plugins> </build> 复制代码
这个模块主要的功能是接口的实现,业务功能的服务提供者。
先来看看该模块的 pom.xml 配置:
<?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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example.dubbo</groupId> <artifactId>dubbo-demo-service</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>dubbo-demo-service</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!-- dubbo provider 启动不成功的主要问题在这里,没有添加 spring-boot-starter-web 依赖,所以启动日志里一直没有显示 “o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8087 (http)” 这行日志输出 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- 这个是定义的接口包,在 provider 和 consumer 都需要引用的 --> <dependency> <groupId>com.example.dubbo</groupId> <artifactId>dubbo-demo-api</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <!-- 新增 dubbo 依赖 --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo</artifactId> <version>2.7.1-SNAPSHOT</version> <exclusions> <exclusion> <artifactId>spring</artifactId> <groupId>org.springframework</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.10</version> <exclusions> <exclusion> <artifactId>slf4j-log4j12</artifactId> <groupId>org.slf4j</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> <version>0.1</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>4.0.1</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> 复制代码
重点要说这里,因为创建模块的时候没有勾选 web 依赖,所以 pom 里只有 spring-boot-starter,并没包含 spring-boot-starter-web 的依赖,启动服务的时候总是完成之后就退出掉,mvn install 也是正常的,百思不得其姐,这里花费了我几个小时的时间。增加完 spring-boot-starter-web 依赖之后,启动日志里就能看到 tomcat 的日志了
o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8087 (http) 复制代码
现在我们来创建一个 DemoApiImpl 类,对 sayHello 方法实现响应:
package com.example.dubbo.demo.service.impl; import com.example.dubbo.demo.api.DemoApi; import org.apache.dubbo.config.annotation.Service; /** * demo 实现类 * * @author jeftom * @date 2019-03-23 23:04 * @since 1.0.0 */ @Service public class DemoApiImpl implements DemoApi { /** * 实现 sayHello 接口 * * @param name * @return */ @Override public String sayHello(String name) { return "Hello, " + name + " (from Spring Boot with dubbo-2.7.1)"; } } 复制代码
DubboDemoServiceApplication 启动类需要增加 dubbo 配置注解:
package com.example.dubbo.demo.service; import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan; import org.apache.dubbo.config.spring.context.annotation.EnableDubboConfig; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * 增加了 EnableDubboConfig 和 DubboComponentScan 的注解,启动时自动扫描 * */ @EnableDubboConfig @DubboComponentScan("com.example.dubbo.demo.service.impl") @SpringBootApplication public class DubboDemoServiceApplication { public static void main(String[] args) { SpringApplication.run(DubboDemoServiceApplication.class, args); } } 复制代码
增加 dubbo 配置文件:
<?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://code.alibabatech.com/schema/dubbo" xsi:schemaLocation=" http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <!-- 定义了提供方应用信息,用于计算依赖关系;在 dubbo-admin 或 dubbo-monitor 会显示这个名字 --> <dubbo:application name="${dubbo.application.name}" owner="jeftom" organization="jeftom" /> <!-- 使用 zookeeper 注册中心暴露服务,注意要先开启 zookeeper--> <dubbo:registry id="zookeeper-registry" protocol="${dubbo.registry.protocol}" address="${dubbo.registry.address}" /> <!-- dubbo协议在20880端口暴露服务 --> <dubbo:protocol name="${dubbo.protocol.name}" port="${dubbo.protocol.port}" accesslog="dubbo-access.log"/> <dubbo:provider retries="0" timeout="30000"/> <dubbo:monitor protocol="registry"/> <!-- 使用 dubbo 协议实现定义好的 Service Api 接口--> <dubbo:service interface="com.example.dubbo.demo.api.DemoApi" ref="DemoApiImpl" retries="0" timeout="60000" /> </beans> 复制代码
spring 项目的 application.properties 配置文件:
spring.config.name=application # spring 的环境配置 spring.profiles.active=dev # 服务启动端口,即内置 tomcat 启动时占用的端口 server.port=8087 #dubbo config #应用定义了提供方应用信息,用于计算依赖关系;在 dubbo-admin 或 dubbo-monitor 会显示这个名字,方便辨识 dubbo.application.name=dubbo-demo-service #应用所属者 dubbo.application.owner=jeftom #应用所属组织 dubbo.application.organization=jeftom # 使用 zookeeper 注册中心暴露服务,注意要先开启 zookeeper # 注册中心id dubbo.registry.id=zookeeper-registry # 注册中心协议 dubbo.registry.protocol=zookeeper # 注册中心地址 dubbo.registry.address=zookeeper.tencus.com:2181 # dubbo协议在20880端口暴露服务 # 协议名称 dubbo.protocol.name=dubbo # 协议端口 dubbo.protocol.port=20880 # 协议访问log dubbo.protocol.accesslog=dubbo-access.log # 重试次数 dubbo.provider.retries=0 # 超时时间 dubbo.provider.timeout=3000 # 注册监控中心 dubbo.monitor.protocol=registry 复制代码
至此,我们的服务提供者已经可以正常启动了,通过 dubbo-admin 可以看到服务已经注册到 zookeeper 里。
这个模块是 dubbo 的 consumer 服务,用于消费提供者提供的服务,服务启动后会与提供者进行连接,完成服务调用。
pom.xml 配置文件:
<?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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example.dubbo</groupId> <artifactId>dubbo-demo-web</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>dubbo-demo-web</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!-- dubbo provider 启动不成功的主要问题在这里,没有添加 spring-boot-starter-web 依赖,所以启动日志里一直没有显示 “o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8087 (http)” 这行日志输出 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- 这个是定义的接口包,在 provider 和 consumer 都需要引用的 --> <dependency> <groupId>com.example.dubbo</groupId> <artifactId>dubbo-demo-api</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <!-- 新增 dubbo 依赖 --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo</artifactId> <version>2.7.1-SNAPSHOT</version> <exclusions> <exclusion> <artifactId>spring</artifactId> <groupId>org.springframework</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.10</version> <exclusions> <exclusion> <artifactId>slf4j-log4j12</artifactId> <groupId>org.slf4j</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> <version>0.1</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>4.0.1</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> 复制代码
spring 应用的 application.properties 配置:
spring.config.name=application # spring 的环境配置 spring.profiles.active=dev # 服务启动端口,即内置 tomcat 启动时占用的端口 server.port=8088 # Qos 运维监控 dubbo.application.qosEnable=true dubbo.application.qosPort=33333 dubbo.application.qosAcceptForeignIp=false # dubbo config # 应用定义了提供方应用信息,用于计算依赖关系;在 dubbo-admin 或 dubbo-monitor 会显示这个名字,方便辨识 dubbo.application.name=dubbo-demo-service # 应用所属者 dubbo.application.owner=jeftom # 应用所属组织 dubbo.application.organization=jeftom # 使用 zookeeper 注册中心暴露服务,注意要先开启 zookeeper # 注册中心id dubbo.registry.id=zookeeper-registry # 注册中心协议 dubbo.registry.protocol=zookeeper # 注册中心地址 dubbo.registry.address=zookeeper.tencus.com:2181 # dubbo协议在20880端口暴露服务 # 协议名称 dubbo.protocol.name=dubbo # 协议端口 dubbo.protocol.port=20880 # 协议访问log dubbo.protocol.accesslog=dubbo-access.log # 重试次数 dubbo.provider.retries=0 # 超时时间 dubbo.provider.timeout=3000 # 注册监控中心 dubbo.monitor.protocol=registry 复制代码
如果同一台机器上同时启动两个服务,会导致 Qos 端口冲突:
main [server.Server] 102 [ERROR] [DUBBO] qos-server can not bind localhost:22222 复制代码
DubboDemoWebApplication 消费者的启动类增加以下两行注解:
@EnableDubboConfig @DubboComponentScan("com.example.dubbo.demo.web.service") 复制代码
分别创建 DemoService 服务类和 DemoController 控制器,
DemoService.java 类
package com.example.dubbo.demo.web.service; import com.example.dubbo.demo.api.DemoApi; import org.apache.dubbo.config.annotation.Reference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; /** * 消费者服务层 * * @author jeftom * @date 2019-03-24 00:49 * @since 1.0.0 */ @Service public class DemoService { private static final Logger LOGGER = LoggerFactory.getLogger(DemoService.class); @Reference private DemoApi demoApi; public String sayHello(String name) { return demoApi.sayHello(name); } } 复制代码
DemoController.java 控制器类
package com.example.dubbo.demo.web.controller; import com.example.dubbo.demo.web.service.DemoService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; /** * demo 控制器 * * @author jeftom * @date 2019-03-24 00:51 * @since 1.0.0 */ @RestController @RequestMapping("/demo") public class DemoController { private static Logger logger = LoggerFactory.getLogger(DemoController.class); @Autowired private DemoService demoService; /** * 测试方法,浏览器访问 /demo/index 可以看到响应结果了 * * @return */ @RequestMapping(value = "/index", method = RequestMethod.GET) @ResponseBody public String index() { return demoService.sayHello("dubbo"); } } 复制代码
好了,现在可以重新 reimport 和 mvn install 一下看看有没有报错,如果没有报了,启动 service 和 web 两个服务,然后打开浏览器访问,撸了这么久,终于出来了。