dataflow论文阅读笔记 Polysh的安装使用 SnappyData排序函数比较 Squirrel-sql客户端连接SnappyData手册 在虚拟机里显示Hello World spark学习博客推荐 SnappyData学习博客和官网文章 Docker常用命令 MyBatis支持的OGNL语法 mysql性能优化 mysql性能优化-优化Sql语句 java各版本新特性 mac上命令行操作 explain输出格式 从文件中读取zk配置——ZooKeeper编程技能(1) git进阶经验-从项目中删除移除的目录 Mongodb 学习之shell命令操作(3) mysql命令 git进阶经验-从多模块项目中分理子模块 从零学hadoop-搭建基础(单点)的Hdfs环境 ZooKeeper集群操作脚本 Vue安装使用 2 初学JVM之问答式记住类加载机制 2 初学JVM之问答式记住虚拟机性能监控与故障处理工具 2 初学JVM之问答式记住垃圾收集器 log4j2 按天生成日志文件 1 初学JVM之问答式记住java自动内存管理 MapReduce学习心得之MapReduce初识 log4j2 日志发送到kafka配置实战 log4j2 日志配置实战 Mongodb 学习之shell命令操作(二) Mongodb 学习之linux版本安装(一) Dubbo的初级使用 ServiceLoader内部实现分析 ServiceLoader 初级应用 log4j日志发送邮件配置实战 红黑树笔记 IDEA首次使用之前的配置 java源码学习之Enum java源码学习之String 自定义Spring tag标签 编写一键发布脚本 记一次Spring Scheduler莫名不执行的一次堆栈分析 kafka的基本操作 nginx 5:Nginx内部变量 nginx 4:Nginx日志管理 提高hadoop配置效率的shell脚本 Hive编程指南之一 Hive的安装 Ambari服务器安装 Ambari服务器管理集群 HBase分布式安装 windows下Eclipse远程调试运行MR程序 基于MapReduce新的API的编程Demo-wordCount window下Eclipse远程只读HDFS上的文件 YARN上节点标签 编写第一个MapReduce的wordcount程序 NodeManager的重启 搭建JStorm集群 YARN上的web应用代理 YARN上的ResourceManager的高可用方案 配置vmware中的虚拟机使用宿主机的共享网络 YARN架构简述 HDFS 架构 Spring的统一异常处理机制 Tomcat 配置服务 HDFS的viewfs指南 HDFS的Federation之路 HDFS基于QJM的HA之路 nginx 3:Nginx反向代理 mybatis操作主体流程 1.正则表达式学习-基础篇 log4j日志配置详解 mysql的时间函数 nginx 2:Nginx模块配置理论及实战 HashMap相关解析和测试文章 工作一年后的面试 用私有构造器或枚举类型强化Singleton属性 java中比较重要的图 mybatis处理枚举类 mybatis集成进spring Spring比较重要的几个截图 21.hadoop-2.7.2官网文档翻译-使用NFS的HDFS高可用性 20.hadoop-2.7.2官网文档翻译-使用仲裁日志管理器的HDFS高可用性 markdown在jekyll中支持的一些操作 Spring项目中配置sl4j和log4j的日志配置 19.hadoop-2.7.2官网文档翻译-HDFS命令指南 Spring的profile机制介绍 mybatis-generator反向生成 18.hadoop-2.7.2官网文档翻译-HDFS用户指南 17.hadoop-2.7.2官网文档翻译-实现Hadoop中Dapper-like追踪 16.hadoop-2.7.2官网文档翻译-Hadoop的KMS(key 管理服务器)-文档集 15.hadoop-2.7.2官网文档翻译-Hadoop的http web认证 14.hadoop-2.7.2官网文档翻译-服务级别的授权指南 13.hadoop-2.7.2官网文档翻译-安全模式中的Hadoop 09.hadoop-2.7.2官网文档翻译-Hadoop命令行微型集群 12.hadoop-2.7.2官网文档翻译-机架感知 11.hadoop-2.7.2官网文档翻译-代理用户-超级用户对其他用户的代表 10.hadoop-2.7.2官网文档翻译-原生库指南 08.hadoop-2.7.2官网文档翻译-文件系统规范 07.hadoop-2.7.2官网文档翻译-Hadoop接口类别 (转)浅析 Decorator 模式,兼谈 CDI Decorator 注解 06.hadoop-2.7.2官网文档翻译-Hadoop的兼容性 05.hadoop-2.7.2官网文档翻译-文件系统命令 04.hadoop-2.7.2官网文档翻译-Hadoop命令指南 03.hadoop-2.7.2官网文档翻译-集群安装 02.hadoop-2.7.2官网文档翻译-单节点集群安装 01.hadoop-2.7.2官网文档翻译-概述 Http 协议相应状态码大全及常用状态码 IDEA快捷键 JDBC Type与Java Type redis 12:redis 操作集合 mybatis-generator错误集合 redis 11:redis 错误集合 nginx 1:nginx的安装 redis 10:redis cluster命令操作 redis 9:redis实例集群安装 java设计模式 hadoop集群学习笔记(1) Apache Shiro 简介 vim编辑神器的进阶命令 Eclipse配置 Eclipse快捷键 Linux 测试题 Linux脚本学习(1) Linux启动简要过程 Centos7上安装Mysql hadoop集群学习笔记(1) (转)分布式发布订阅消息系统 Kafka 架构设计 maven 命令 Kafka集群安装 Kafka初步使用 redis 8:redis server 和 scripting命令操作 redis 7:redis transaction 和 connection命令操作 redis 6:redis hash 命令操作 redis 5:redis sorted_set 命令操作 搭建本地Jekyll+Markdown+Github的开发环境 Spring源码阅读笔记(2) redis 4:redis set命令操作 Spring添加任务调度配置 redis 3:Redis list命令操作 redis 2:redis 一般命令操作 redis 1:redis单机安装笔记 redis 0:redis配置属性描述 Spring源码阅读笔记(1) spark 错误集锦 spark集群安装 Linux 基本命令操作 Hadoop错误信息处理 Hadoop代码拾忆 从零开始搭建spring-springmvc-mybatis-mysql和dubbo项目 java知识点札记 java排错 Google Java Style 中文版 git进阶经验 github使用经验 MongoDB用户角色授权与AUTH启用 MongoDB 命令 MongoDB 特定规范 Spring MVC实现跳转的几种方式 史上最全最强SpringMVC详细示例实战教程 Spring 零星笔记 js中(function(){…})()立即执行函数写法理解 如何解决跨域问题 创建ajax简单过程 前端定位 设置MYSQL允许通过IP访问 mybatis异常 :元素内容必须由格式正确的字符数据或标记组成 如何为 WordPress 绑定多个域名的方法s WordPress工作原理之程序文件执行顺序(传说中的架构源码分析) Spring源码导入Eclipse中 基于PHPnow搭建Eclipse开发环境 解决wordpress首页文章内容截断处理的几种方法 ZooKeeper理论知识 ZooKeeper集群安装配置 Git常用命令速查表 Linux 4:磁盘与文件系统管理 Linux 3:文件与目录管理 Linux 2:文件权限与目录配置 Markdown输入LaTeX数学公式
从零学hadoop-搭建基础(单点)的Hdfs环境 MapReduce学习心得之MapReduce初识 Ambari服务器安装 Ambari服务器管理集群 windows下Eclipse远程调试运行MR程序 基于MapReduce新的API的编程Demo-wordCount window下Eclipse远程只读HDFS上的文件 YARN上节点标签 编写第一个MapReduce的wordcount程序 NodeManager的重启 YARN上的web应用代理 YARN上的ResourceManager的高可用方案 YARN架构简述 HDFS 架构 HDFS的viewfs指南 HDFS的Federation之路 HDFS基于QJM的HA之路 21.hadoop-2.7.2官网文档翻译-使用NFS的HDFS高可用性 20.hadoop-2.7.2官网文档翻译-使用仲裁日志管理器的HDFS高可用性 19.hadoop-2.7.2官网文档翻译-HDFS命令指南 18.hadoop-2.7.2官网文档翻译-HDFS用户指南 17.hadoop-2.7.2官网文档翻译-实现Hadoop中Dapper-like追踪 16.hadoop-2.7.2官网文档翻译-Hadoop的KMS(key 管理服务器)-文档集 15.hadoop-2.7.2官网文档翻译-Hadoop的http web认证 14.hadoop-2.7.2官网文档翻译-服务级别的授权指南 13.hadoop-2.7.2官网文档翻译-安全模式中的Hadoop 09.hadoop-2.7.2官网文档翻译-Hadoop命令行微型集群 12.hadoop-2.7.2官网文档翻译-机架感知 11.hadoop-2.7.2官网文档翻译-代理用户-超级用户对其他用户的代表 10.hadoop-2.7.2官网文档翻译-原生库指南 08.hadoop-2.7.2官网文档翻译-文件系统规范 07.hadoop-2.7.2官网文档翻译-Hadoop接口类别 06.hadoop-2.7.2官网文档翻译-Hadoop的兼容性 05.hadoop-2.7.2官网文档翻译-文件系统命令 04.hadoop-2.7.2官网文档翻译-Hadoop命令指南 03.hadoop-2.7.2官网文档翻译-集群安装 02.hadoop-2.7.2官网文档翻译-单节点集群安装 01.hadoop-2.7.2官网文档翻译-概述 hadoop集群学习笔记(1) hadoop集群学习笔记(1) Hadoop错误信息处理 Hadoop代码拾忆

Dubbo的初级使用

2017年04月23日
摘要:记录对Dubbo的基本使用。

1.背景

闲话就不讲了,Dubbo官网[Dubbo.io]已经阐述的很详细了,接下来直接实战应用Dubbo开发分布式服务。我所理解的分布式服务就是调用方和提供方可以不在同一个进程内甚至不在同一台机器,同一网段内,每次服务的调用都会经过网络传输。

2.实战

maven项目模块划分

以我的demo项目为例:

  • 父模块[brief-dubbo]

    一些各模块共用的配置(包括资源配置和POM配置)或代码。

  • 接口模块[brief-dubbo-api]

    提供消费方和提供方共用的接口和POJO类,该模块需要被customer和service模块依赖。

  • 服务调用方(消费方)模块[brief-dubbo-customer],以下简称customer模块。

    编写调用服务的代码,不关心服务的内部逻辑,只关心接口来处理自己内部的逻辑。

  • 服务提供方模块[brief-dubbo-service],以下简称service模块。

    编写接口内部实现,为服务调用方提供接口的功能,封装并隐藏内部实现。

2.1 brief-dubbo的POM配置

<properties>
    <dubbo.version>2.5.3</dubbo.version>
    <fastjson.version>1.2.17</fastjson.version>
    <slf4j.version>1.7.2</slf4j.version>
    <junit.version>4.12</junit.version>
    <log4j.version>1.2.17</log4j.version>
    <lombok.version>1.16.8</lombok.version>
    <spring.version>4.3.2.RELEASE</spring.version>
    <zkclient_version>0.1</zkclient_version>
    <zookeeper_version>3.4.9</zookeeper_version>
 </properties>
<dependencies>
  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>${lombok.version}</version>
  </dependency>

  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>${spring.version}</version>
  </dependency>
</dependencies>

<dependencies>
  <!--为每个子项目都引入日志依赖-->
  <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>jcl-over-slf4j</artifactId>
      <version>${slf4j.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>

  <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>${junit.version}</version>
  </dependency>
</dependencies>

2.2 brief-dubbo-api模块配置

2.2.1 POM配置

引入customer和service都会用到的依赖包

<dependencies>
    <!-- spring相关 -->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <exclusions>
        <exclusion>
          <groupId>org.springframework</groupId>
          <artifactId>spring-web</artifactId>
        </exclusion>
      </exclusions>
  </dependency>
  <!-- fastjson -->
  <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
  </dependency>
  <!-- dubbo -->
  <dependency> 
      <groupId>com.alibaba</groupId>
      <artifactId>dubbo</artifactId>
      <exclusions>
      <exclusion>
        <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
      </exclusion>
      <exclusion>
        <groupId>org.springframework</groupId>
  <artifactId>spring</artifactId>
      </exclusion>
      </exclusions>
  </dependency>
  <!-- ZooKeeper及客户端 -->
  <dependency>
      <groupId>com.github.sgroschupf</groupId>
      <artifactId>zkclient</artifactId>
      <exclusions>
        <exclusion>
          <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        </exclusion>
      </exclusions>
  </dependency>
  <dependency>
      <groupId>org.apache.zookeeper</groupId>
      <artifactId>zookeeper</artifactId>
      <exclusions>
        <exclusion>
          <groupId>io.netty</groupId>
        <artifactId>netty</artifactId>
        </exclusion>
        <exclusion>
          <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
      </exclusions>
  </dependency>

  <!-- aspectjweaver -->
  <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
  </dependency>
</dependencies>

2.2.2 编写代码

在brief-dubbo-api模块下src/main/java目录下创建接口cn.followtry.dubbo.api.UserService和POJO类cn.followtry.dubbo.bean.User

package cn.followtry.dubbo.api;
import cn.followtry.dubbo.bean.User;
public interface UserService{
  User getUserById(String id);
}
package cn.followtry.dubbo.bean;
import java.io.Serializable;
import lombok.Data;
import lombok.ToString;

@Data
@ToString
public class User implements Serializable {
  private static final long serialVersionUID = 3899555909604815507L;
  private String name;
  private String id;
}

这样,简单的UserService的API接口就已经定义好了,接下来配置service模块并实现接口逻辑。

2.3 service模块配置

2.3.1 POM配置

因前面已经做了工作,所以此处配置较少。

<packaging>war</packaging>
<dependencies>
    <dependency>
      <groupId>cn.followtry</groupId>
      <artifactId>brief-dubbo-api</artifactId>
      <version>${project.version}</version>
    </dependency>
</dependencies>
<build>
  <!-- 指定构建的资源及构建的位置 -->
  <resources>
    <resource>
      <directory>src/main/java</directory>
      <targetPath>${project.build.directory}</targetPath>
      <includes>
        <include>**/*.java</include>
      </includes>
    </resource>
    <resource>
      <directory>src/main/resources</directory>
      <filtering>true</filtering>
    </resource>
  </resources>
</build>

2.3.2 web.xml配置

src/main/webapp/WEB-INF下创建web.xml文件并配置如下内容:

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
  <display-name>developer</display-name>

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <!--Spring的主配置文件-->
    <param-value>
      classpath*:spring/applicationContext.xml
    </param-value>
  </context-param>
  <!--Spring启动类-->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <!--设置全局编码-->
  <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>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

2.3.3 资源文件创建

src/main/resources目录下创建spring/applicationContext.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: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/context http://www.springframework.org/schema/context/spring-context.xsd">

  <context:annotation-config/>
  <!--启用注解扫描指定包及其子包下的类-->
  <context:component-scan base-package="cn.followtry.dubbo"/>
</beans>

src/main/resources目录下创建log4j.properties日志配置文件

log4j.rootLogger=info, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
#log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %t %c{2}:%L - %m%n
log4j.appender.stdout.Threshold
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p %l - %m%n

2.3.4 编写代码

新建类cn.followtry.dubbo.impl.UserServiceImpl实现cn.followtry.dubbo.api.UserService接口

package cn.followtry.dubbo.impl;

import cn.followtry.dubbo.api.UserService;
import cn.followtry.dubbo.bean.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Service("userService")
@Slf4j
public class UserServiceImpl implements UserService {

  public UserServiceImpl() {
    log.info("cn.followtry.dubbo.impl.UserServiceImpl.UserServiceImpl()");
  }

  @Override
  public User getUserById(String id) {
    //demo code
    User user = new User();
    if (id != null && !"".equals(id)) {
      user.setId(id);
      user.setName("hello world");
      return user;
    }
    user.setName("user is not found");
    return user;
  }
}

到这最基本最普通的服务端代码就写好了,但是为什么没有看到Dubbo的配置呢,这样就能部署为分布式服务了吗?当然不能,继续天啊及提供方的Dubbo配置。

2.3.5 服务提供方Dubbo配置(xml配置方式)

首先提一下,注册中心ZooKeeper集群搭建请看这里。

当前ZooKeeper集群有三个节点192.168.2.203,192.168.2.202,192.168.2.201

src/main/resources/spring目录下创建dubbo-provider.xml文件,用来配置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://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

       <!--每个标签的具体含义请查看Dubbo官网-->

  <dubbo:application name="dubbo-provider-demo" owner="jingzz" organization="followtry" />

  <!-- 服务注册中心,即ZooKeeper集群;address地址为host:port,中间用逗号分隔-->
  <dubbo:registry protocol="zookeeper" address="192.168.2.203:2181,192.168.2.201:2181,192.168.2.202:2181"/>

  <dubbo:protocol name="dubbo" port="28080" contextpath="services" accesslog="true"/>

  <!-- 暴露服务 -->
  <!--
    spring已经注解扫描了基础包,即不用再次手写实例bean了(bean的实例化与dubbo:service的先后位置无关)
    如果接口实现类没有自定义service name,则使用实现类名称(首字母小写)作为ref,否则使用自定义名称。
    如:对于UserServiceImpl implements UserService,在@Service注解中指定名称userSerivce则使用指定名称userService,否则使用userServiceImpl(这是SpringIOC容器实例化bean时的命名生成规则决定的)。
   -->
  <dubbo:service interface="cn.followtry.dubbo.api.UserService" connections="1" executes="300" ref="userService"/>

</beans>

applicationContext.xml中加一句<import resource="dubbo-provider.xml"/>,以便引入dubbo-provider.xml的配置。

这次Dubbo服务提供方真的可以在注册中心注册了。在Tomcat下部署并启动service模块。部分打印日志如下:


[DUBBO] Export dubbo service cn.followtry.dubbo.api.UserService to local registry, dubbo version: 2.5.3, current host: 127.0.0.1

[DUBBO] Export dubbo service cn.followtry.dubbo.api.UserService to url dubbo://192.168.31.1:28080/services/cn.followtry.dubbo.api.UserService?accesslog=true&anyhost=true&application=dubbo-provider-demo&dubbo=2.5.3&group=primary&interface=cn.followtry.dubbo.api.UserService&methods=getUserById&organization=followtry&owner=jingzz&pid=213160&revision=0.0.3&side=provider&timestamp=1492965068638, dubbo version: 2.5.3, current host: 127.0.0.1

[DUBBO] Register dubbo service cn.followtry.dubbo.api.UserService url dubbo://192.168.31.1:28080/services/cn.followtry.dubbo.api.UserService?accesslog=true&anyhost=true&application=dubbo-provider-demo&dubbo=2.5.3&group=primary&interface=cn.followtry.dubbo.api.UserService&methods=getUserById&organization=followtry&owner=jingzz&pid=213160&revision=0.0.3&side=provider&timestamp=1492965068638 to registry registry://192.168.2.203:2181/com.alibaba.dubbo.registry.RegistryService?application=dubbo-provider-demo&backup=192.168.2.201:2181,192.168.2.202:2181&dubbo=2.5.3&organization=followtry&owner=jingzz&pid=213160&registry=zookeeper&timestamp=1492965068638, dubbo version: 2.5.3, current host: 127.0.0.1

[DUBBO] Register: dubbo://192.168.31.1:28080/services/cn.followtry.dubbo.api.UserService?accesslog=true&anyhost=true&application=dubbo-provider-demo&dubbo=2.5.3&group=primary&interface=cn.followtry.dubbo.api.UserService&methods=getUserById&organization=followtry&owner=jingzz&pid=213160&revision=0.0.3&side=provider&timestamp=1492965068638, dubbo version: 2.5.3, current host: 127.0.0.1

[DUBBO] Subscribe: provider://192.168.31.1:28080/services/cn.followtry.dubbo.api.UserService?accesslog=true&anyhost=true&application=dubbo-provider-demo&category=configurators&check=false&dubbo=2.5.3&group=primary&interface=cn.followtry.dubbo.api.UserService&methods=getUserById&organization=followtry&owner=jingzz&pid=213160&revision=0.0.3&side=provider&timestamp=1492965068638, dubbo version: 2.5.3, current host: 127.0.0.1

[DUBBO] Notify urls for subscribe url provider://192.168.31.1:28080/services/cn.followtry.dubbo.api.UserService?accesslog=true&anyhost=true&application=dubbo-provider-demo&category=configurators&check=false&dubbo=2.5.3&group=primary&interface=cn.followtry.dubbo.api.UserService&methods=getUserById&organization=followtry&owner=jingzz&pid=213160&revision=0.0.3&side=provider&timestamp=1492965068638, urls: [empty://192.168.31.1:28080/services/cn.followtry.dubbo.api.UserService?accesslog=true&anyhost=true&application=dubbo-provider-demo&category=configurators&check=false&dubbo=2.5.3&group=primary&interface=cn.followtry.dubbo.api.UserService&methods=getUserById&organization=followtry&owner=jingzz&pid=213160&revision=0.0.3&side=provider&timestamp=1492965068638], dubbo version: 2.5.3, current host: 127.0.0.1

[DUBBO] The service ready on spring started. service: cn.followtry.dubbo.api.UserService, dubbo version: 2.5.3, current host: 127.0.0.1

这样服务已经暴露给调用方,只等调用方调用即可了。那赶紧编写调用方代码测试下服务是否发布成功吧。

2.4 customer模块配置

2.4.1 POM配置

<packaging>war</packaging>
<dependencies>
    <dependency>
        <groupId>cn.followtry</groupId>
        <artifactId>brief-dubbo-api</artifactId>
        <version>${project.version}</version>
    </dependency>
</dependencies>
<build>
    <!-- 指定构建的资源及构建的位置 -->
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <targetPath>${project.build.directory}</targetPath>
            <includes>
                <include>**/*.java</include>
            </includes>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

2.4.1 消费方的资源文件配置

src/main/resources创建applicationContext.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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="
	      http://www.springframework.org/schema/beans
		    http://www.springframework.org/schema/beans/spring-beans.xsd
       	http://www.springframework.org/schema/aop
       	http://www.springframework.org/schema/aop/spring-aop.xsd 
       	http://www.springframework.org/schema/context 
       	http://www.springframework.org/schema/context/spring-context.xsd">

  <context:annotation-config/>
  <context:component-scan base-package="cn.followtry.dubbo"/>
  <!-- 放弃JDK的动态代理,而使用cglib  -->
  <aop:aspectj-autoproxy proxy-target-class="true"/>
  <!--引入消费方的Dubbo配置-->
  <import resource="dubbo-consumer.xml"/>
</beans>

日志配置参考服务方的2.3.3段

2.4.2 服务调用方Dubbo配置(xml方式)

src/main/resources创建dubbo-consumer.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://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

  <dubbo:application name="customer" owner="jingzz" organization="followtry"/>

  <dubbo:registry protocol="zookeeper" address="192.168.2.203:2181,192.168.2.201:2181,192.168.2.202:2181"/>

  <dubbo:protocol name="dubbo" port="28080" contextpath="services" accepts="10"/>

  <dubbo:reference  id="userService"  interface="cn.followtry.dubbo.api.UserService"/>

</beans>

既然配置好了,那就需要写代码调一调测试下服务是否可以被分布式访问了。

2.4.3 编写代码

调用代码

package cn.followtry.dubbo.customer;

import cn.followtry.dubbo.api.UserService;
import cn.followtry.dubbo.bean.User;
import com.alibaba.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class ServiceHandler {
  @Autowired
  @Qualifier("userService")
  private UserService userService;

  public User getUser(String id) {
    return userService.getUserById(id);
  }
}

测试代码

package cn.followtry.dubbo.customer.core;

import cn.followtry.dubbo.bean.User;
import cn.followtry.dubbo.customer.ServiceHandler;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath*:applicationContext.xml")
public class ApplicationBoot {

  @Autowired
  private ServiceHandler serviceHandler;

  @Test
  public void testUser() {
    User jingzz = serviceHandler.getUser("zhangsan");
    System.out.println(jingzz);
  }
}

调用后返回结果为:

User(name=hello world, id=zhangsan)

说明调用正确,服务确实可以远程访问了。那用Spring web方式是否可以访问呢,肯定可以不过限于篇幅。读者只好动手自己试试喽!

问题来了,那如果我有多个服务接口,那么是不是在service和customer模块各添加很多的配置,岂不是配置文件难以控制,有没有可以配置自动扫描指定注解方式替代手工配置方式呢?这个必须有,继续向下看。

2.5 优化代码

2.5.1 优化service模块

修改service模块的dubbo配置,将手工注入修改为自动扫描方式。

添加如下配置:

 <!--
  注解方式指定要暴露的包下的服务。
    内部实现是调用了Spring的ClassPathBeanDefinitionScanner类的scan接口,
    可以和<context:component-scan base-package="cn.followtry.dubbo"/>注解一样自动扫描注册bean。
    而需要暴露的服务调用的注解为@com.alibaba.dubbo.config.annotation.Service
  -->
  <dubbo:annotation package="cn.followtry.dubbo"/>

注释掉

<dubbo:service interface="cn.followtry.dubbo.api.UserService" connections="1" executes="300" ref="userService"/>

代码得做相应调整,加上dubbo规定的注解@com.alibaba.dubbo.config.annotation.Service(interfaceClass = UserService.class)

重启服务。

2.5.2 优化customer模块

添加

<!--注解方式实例化对com.alibaba.dubbo.config.annotation.Reference注解的属性-->
  <dubbo:annotation package="cn.followtry.dubbo"/>

移除<dubbo:reference id="userService" interface="cn.followtry.dubbo.api.UserService"/>

代码修改,得调整注解如下


package cn.followtry.dubbo.customer;

import cn.followtry.dubbo.api.UserService;
import cn.followtry.dubbo.bean.User;
import com.alibaba.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;

@Service
public class ServiceHandler {

  public User getUser(String id) {
    return userService.getUserById(id);
  }

//  @Autowired
//  @Qualifier("userService")
//使用dubbo定义的直接Reference解释该属性
  @Reference(interfaceClass = UserService.class)
  private UserService userService;
}

好的,运行下测试代码,应该是能得出正确结果的。到这里以后写暴露服务就省很多事情了。那么问题又来了,如果一个接口有多个实现的时候我怎么调用呢?嗯,这个嘛,有办法,通过为服务指定group属性,来区分同一接口的不同实现。

2.5.4 解决接口多实现的调用问题

因为多实现的调用会有序列化问题,所以接口UserService要继承Serializable接口

服务端

原实现的Service注解的group参数指定为”primary”,并新创建类


package cn.followtry.dubbo.impl;

import cn.followtry.dubbo.api.UserService;
import cn.followtry.dubbo.bean.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Service("customUserService")
//指定group为custom
@com.alibaba.dubbo.config.annotation.Service(interfaceClass = UserService.class,export = true,group = "custom")
@Slf4j
public class CustomUserServiceImpl implements UserService {
  public CustomUserServiceImpl() {
    log.info("cn.followtry.dubbo.api.UserService.CustomUserServiceImpl.CustomUserServiceImpl()");
  }

  @Override
  public User getUserById(String id) {
    return new User() {
      {
        setId(id);
        setName("custom-user-1");
      }
    };
  }
}

消费端

都不用动配置, 只要在注入属性的地方注解Reference添加上相应的group属性即可。

调用代码添加

//  @Autowired
@Reference(interfaceClass = UserService.class,group = "custom")
private UserService customUserService;
public User getUser2(String id) {
  return customUserService.getUserById(id);
}

测试代码添加调用

User zhangsan2 = serviceHandler.getUser2("zhangsan2");
System.out.println(zhangsan2);

返回结果为

User(name=hello world, id=zhangsan)
User(name=custom-user-1, id=zhangsan2)

总结

好了,dubbo的使用就简单的介绍到这里吧。夜里加班了两个班小时才搞完。这只是dubbo的入门,详细使用说明还是需要参考官网文档,极其详细。