☆聊聊Dubbo(二):简单入门

0 准备

  1. 安装注册中心:Zookeeper、Dubbox自带的dubbo-registry-simple;
  2. 安装DubboKeeper监控:https://github.com/dubboclub/dubbokeeper;

以上两点准备,不是本文重点,不做详细介绍,安装比较简单,自行查阅相关资料安装学习。

1 服务端

1.2 接口定义

  1. 创建Maven模块:msa-demo-api

    ☆聊聊Dubbo(二):简单入门_第1张图片
    msa-demo-api
  2. msa-demo-api:配置pom.xml

    
    
        com.alibaba
        dubbo
        2.8.4
    
    
    
    
    
         org.projectlombok
         lombok
    
    
    
    
    
        org.jboss.resteasy
        resteasy-jaxrs
        3.0.7.Final
    
    
        org.jboss.resteasy
        resteasy-client
        3.0.7.Final
    
    
        javax.validation
        validation-api
        1.0.0.GA
    
    
    
    
    
        org.jboss.resteasy
        resteasy-jackson-provider
        3.0.7.Final
    
    
    
    
    
        org.jboss.resteasy
        resteasy-jaxb-provider
        3.0.7.Final
    
    
    
    
    
        org.jboss.resteasy
        resteasy-netty
        3.0.7.Final
    
    
    
    
    
        org.jboss.resteasy
        resteasy-jdk-http
        3.0.7.Final
    
    
    
    
    
        org.apache.tomcat.embed
        tomcat-embed-core
        8.0.11
    
    
        org.apache.tomcat.embed
        tomcat-embed-logging-juli
        8.0.11
    
    
    
    
    
        com.esotericsoftware.kryo
        kryo
        2.24.0
    
    
        de.javakaffee
        kryo-serializers
        0.26
    
    
    
    
    
        de.ruedigermoeller
        fst
        1.55
    
    
    
    
    
        com.fasterxml.jackson.core
        jackson-core
        2.3.3
    
    
        com.fasterxml.jackson.core
        jackson-databind
        2.3.3
    
    
    

    以上POM配置,从dubbox-2.8.4开始,所有依赖库的使用方式将和dubbo原来的一样:即如果要使用REST、Kyro、FST、Jackson等功能,需要用户自行手工添加相关的依赖。

  3. 定义接口:UserService.java

    /**
     * @author TaoBangren
     * @version 1.0
     * @since 2017/5/17 上午9:26
     */
    public interface UserService {
        User getUser(Long id);
        Long registerUser(User user);
    }
    
  4. 定义REST接口:AnotherUserRestService.java

    package com.alibaba.dubbo.demo.user.facade;
    import com.alibaba.dubbo.demo.user.User;
    import com.alibaba.dubbo.rpc.protocol.rest.support.ContentType;
    import javax.validation.constraints.Min;
    import javax.ws.rs.*;
    import javax.ws.rs.core.MediaType;
    /**
     * @author TaoBangren
     * @version 1.0
     * @since 2017/5/17 上午9:26
     */
    // 在Dubbo中开发REST服务主要都是通过JAX-RS的annotation来完成配置的,
    // 在上面的示例中,我们都是将annotation放在服务的实现类中。但其实,我
    // 们完全也可以将annotation放到服务的接口上,这两种方式是完全等价的.
    //
    // 在一般应用中,我们建议将annotation放到服务实现类,这样annotation和
    // java实现代码位置更接近,更便于开发和维护。另外更重要的是,我们一般倾向
    // 于避免对接口的污染,保持接口的纯净性和广泛适用性。
    // 但是,如后文所述,如果我们要用dubbo直接开发的消费端来访问此服务,则annotation必须放到接口上。
    // 如果接口和实现类都同时添加了annotation,则实现类的annotation配置会生效,接口上的annotation被直接忽略。
    @Path("u")
    @Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})
    @Produces({ContentType.APPLICATION_JSON_UTF_8, ContentType.TEXT_XML_UTF_8})
    public interface AnotherUserRestService {
    
          @GET
          @Path("{id : \\d+}")
          // 在一个REST服务同时对多种数据格式支持的情况下,根据JAX-RS标准,
          // 一般是通过HTTP中的MIME header(content-type和accept)来指定当前想用的是哪种格式的数据。
          // @Produces({ContentType.APPLICATION_JSON_UTF_8, ContentType.TEXT_XML_UTF_8})
          // 但是在dubbo中,我们还自动支持目前业界普遍使用的方式,即用一个URL后缀(.json和.xml)来指定
          // 想用的数据格式。例如,在添加上述annotation后,直接访问http://localhost:8888/users/1001.json
          // 则表示用json格式,直接访问http://localhost:8888/users/1002.xml则表示用xml格式,
          // 比用HTTP Header更简单直观。Twitter、微博等的REST API都是采用这种方式。
          // 如果你既不加HTTP header,也不加后缀,则dubbo的REST会优先启用在以上annotation定义中排位最靠前的那种数据格式。
          // 注意:这里要支持XML格式数据,在annotation中既可以用MediaType.TEXT_XML,也可以用MediaType.APPLICATION_XML,
          // 但是TEXT_XML是更常用的,并且如果要利用上述的URL后缀方式来指定数据格式,只能配置为TEXT_XML才能生效。
          User getUser(@PathParam("id") @Min(1L) Long id);
    
          @POST
          @Path("register")
          RegistrationResult registerUser(User user);
    }
    
  5. 定义实体:User.java

    package com.alibaba.dubbo.demo.user;
    import lombok.Data;
    import org.codehaus.jackson.annotate.JsonProperty;
    import javax.validation.constraints.Min;
    import javax.validation.constraints.NotNull;
    import javax.validation.constraints.Size;
    import javax.xml.bind.annotation.XmlAccessType;
    import javax.xml.bind.annotation.XmlAccessorType;
    import javax.xml.bind.annotation.XmlElement;
    import javax.xml.bind.annotation.XmlRootElement;
    import java.io.Serializable;
    /**
     * @author TaoBangren
     * @version 1.0
     * @since 2017/5/17 上午9:26
     */
    // 由于JAX-RS的实现一般都用标准的JAXB(Java API for XML Binding)来序列化和反序列化XML格式数据,
    // 所以我们需要为每一个要用XML传输的对象添加一个类级别的JAXB annotation(@XmlRootElement) ,否则序列化将报错。
    @Data
    @XmlRootElement
    @XmlAccessorType(XmlAccessType.FIELD)
    public class User implements Serializable {
    
          @NotNull
          @Min(1L)
          private Long id;
    
          // REST的底层实现会在service的对象和JSON/XML数据格式之间自动做序列化/反序列化。
          // 但有些场景下,如果觉得这种自动转换不满足要求,可以对其做定制。
          // Dubbo中的REST实现是用JAXB做XML序列化,用Jackson做JSON序列化,
          // 所以在对象上添加JAXB或Jackson的annotation即可以定制映射。
          @JsonProperty("username")
          @XmlElement(name = "username")
          @NotNull
          @Size(min = 6, max = 50)
          private String name;
    }
    
  6. 定义REST响应结果实体:RegistrationResult.java

    package com.alibaba.dubbo.demo.user.facade;
    import lombok.Data;
    import javax.xml.bind.annotation.XmlRootElement;
    import java.io.Serializable;
    /**
     * @author TaoBangren
     * @version 1.0
     * @since 2017/5/17 上午9:26
     */
    // 此外,如果service方法中的返回值是Java的 primitive类型(如int,long,float,double等),
    // 最好为它们添加一层wrapper对象,因为JAXB不能直接序列化primitive类型。这样不但能够解决XML序列化的问题,
    // 而且使得返回的数据都符合XML和JSON的规范。
    // 这种wrapper对象其实利用所谓Data Transfer Object(DTO)模式,采用DTO还能对传输数据做更多有用的定制。
    @Data
    @XmlRootElement
    public class RegistrationResult implements Serializable {
          private Long id;
    }
    

1.3 服务实现

  1. 创建Maven模块:msa-demo-provider

    ☆聊聊Dubbo(二):简单入门_第2张图片
    msa-demo-provider
  2. msa-demo-provider:配置pom.xml

    
    
         com.alibaba
         msa-demo-api
         1.0-SNAPSHOT
    
    
    
  3. 实现UserService接口:UserServiceImpl.java

    package com.alibaba.dubbo.demo.user;
    import lombok.extern.slf4j.Slf4j;
    import java.util.concurrent.atomic.AtomicLong;
    /**
     * @author TaoBangren
     * @version 1.0
     * @since 2017/5/17 上午9:26
     */
    @Slf4j
    public class UserServiceImpl implements UserService {
          private final AtomicLong idGen = new AtomicLong();
          public User getUser(Long id) {
              User user = new User();
              user.setId(id);
              user.setName("username" + id);
              return user;
          }
      
          public Long registerUser(User user) {
              // System.out.println("Username is " + user.getName());
              return idGen.incrementAndGet();
          }
    }
    
  4. 实现REST接口AnotherUserRestService:AnotherUserRestServiceImpl.java

    package com.alibaba.dubbo.demo.user.facade;
    import com.alibaba.dubbo.demo.user.User;
    import com.alibaba.dubbo.demo.user.UserService;
    import com.alibaba.dubbo.rpc.RpcContext;
    import lombok.extern.slf4j.Slf4j;
    /**
     * @author TaoBangren
     * @version 1.0
     * @since 2017/5/17 上午9:26
     */
    @Slf4j
    public class AnotherUserRestServiceImpl implements AnotherUserRestService {
    
          private UserService userService;
    
          public void setUserService(UserService userService) {
              this.userService = userService;
          }
    
          public User getUser(Long id) {
              System.out.println("Client name is " + RpcContext.getContext().getAttachment("clientName"));
              System.out.println("Client impl is " + RpcContext.getContext().getAttachment("clientImpl"));
              return userService.getUser(id);
          }
    
          public RegistrationResult registerUser(User user) {
              Long id = userService.registerUser(user);
              RegistrationResult registrationResult = new RegistrationResult();
              registrationResult.setId(id);
              return registrationResult;
          }
    }
    
  5. Dubbox与Spring集成配置:msa-demo-provider.xml

     
     
    
         
         
         
    
         
         
         
    
         
     
         
    
         
         
    
         
     
         
         
         
      
         
         
     
         
         
      
         
     
         
             
         
     
         
    
    
  6. 配置dubbo.properties

    #dubbo.container=log4j,spring
    #dubbo.application.name=demo-provider
    #dubbo.application.owner=
    #dubbo.registry.address=multicast://224.5.6.7:1234
    #dubbo.registry.address=zookeeper://127.0.0.1:2181
    #dubbo.registry.address=redis://127.0.0.1:6379
    #dubbo.registry.address=dubbo://127.0.0.1:9090
    #dubbo.monitor.protocol=registry
    #dubbo.protocol.name=dubbo
    #dubbo.protocol.port=20880
    #dubbo.service.loadbalance=roundrobin
    #dubbo.log4j.file=logs/msa-demo-provider.log
    #dubbo.log4j.level=INFO
    #dubbo.log4j.subdirectory=20880
    dubbo.application.logger=slf4j
    dubbo.spring.config=classpath*:msa-*.xml
    

1.4 服务启动

定义服务启动类

package com.alibaba.dubbo.demo.provider;
/**
  * @author TaoBangren
  * @version 1.0
  * @since 2017/5/17 上午9:26
  */
public class DemoProvider {
      public static void main(String[] args) {
          com.alibaba.dubbo.container.Main.main(args);
      }
}

执行main方法启动,看到以下日志输出时,msa-demo-provider启动成功:

☆聊聊Dubbo(二):简单入门_第3张图片
msa-demo-provider启动成功

查看DubboKeeper监控大盘,msa-demo-provider发布服务成功,可以看到我们发布的两个接口:

☆聊聊Dubbo(二):简单入门_第4张图片
msa-demo-provider发布服务成功

2. 客户端

  1. 创建Maven模块:msa-demo-client

    ☆聊聊Dubbo(二):简单入门_第5张图片
    msa-demo-client
  2. msa-demo-client:配置pom.xml

    
    
         com.alibaba
         msa-demo-api
         1.0-SNAPSHOT
    
    
    
  3. Dubbox与Spring集成配置:msa-demo-client.xml

    
    
    
       
       
    
       
       
       
     
       
       
    
       
    
    

3. 消费端

3.1 消费端实现

  1. 创建Maven模块:msa-demo-consumer

    ☆聊聊Dubbo(二):简单入门_第6张图片
    msa-demo-consumer
  2. msa-demo-consumer:配置pom.xml

    
    
          com.jeasy
          msa-demo-client
          1.0-SNAPSHOT
    
    
    
  3. 创建消费端测试类:DemoAction.java

    package com.alibaba.dubbo.demo;
    import com.alibaba.dubbo.rpc.RpcContext;
    import com.alibaba.dubbo.demo.user.User;
    import com.alibaba.dubbo.demo.user.UserService;
    import com.alibaba.dubbo.demo.user.facade.AnotherUserRestService;
    /**
     * @author TaoBangren
     * @version 1.0
     * @since 2017/5/17 上午9:26
     */
    public class DemoAction {
    
          private UserService userService;
    
          private AnotherUserRestService anotherUserRestService;
    
          public void setUserService(final UserService userService) {
              this.userService = userService;
          }
    
          public void setAnotherUserRestService(final AnotherUserRestService anotherUserRestService) {
              this.anotherUserRestService = anotherUserRestService;
          }
    
          public void start() throws Exception {
              User user = new User();
              user.setId(1L);
              user.setName("larrypage");
    
              System.out.println("SUCCESS: registered user with id by rest" + anotherUserRestService.registerUser(user).getId());
              System.out.println("SUCCESS: registered user with id " + userService.registerUser(user));
     
              RpcContext.getContext().setAttachment("clientName", "demo");
              RpcContext.getContext().setAttachment("clientImpl", "dubbox rest");
              System.out.println("SUCCESS: got user by rest" + anotherUserRestService.getUser(1L));
              System.out.println("SUCCESS: got user " + userService.getUser(1L));
          }
    }
    
  4. Dubbox与Spring集成配置:msa-demo-consumer.xml

    
    
    
       
       
    
       
       
       
    
       
           
           
       
    
    
  5. 配置dubbo.properties

    #dubbo.container=log4j,spring
    #dubbo.application.name=demo-consumer
    #dubbo.application.owner=
    #dubbo.registry.address=multicast://224.5.6.7:1234
    #dubbo.registry.address=zookeeper://127.0.0.1:2181
    #dubbo.registry.address=redis://127.0.0.1:6379
    #dubbo.registry.address=dubbo://127.0.0.1:9090
    #dubbo.monitor.protocol=registry
    #dubbo.log4j.file=logs/msa-demo-consumer.log
    #dubbo.log4j.level=INFO
    dubbo.application.logger=slf4j
    dubbo.spring.config=classpath*:msa-*.xml
    

3.2 消费端测试

定义消费启动类:

package com.jeasy;
/**
 * @author TaoBangren
 * @version 1.0
 * @since 2017/5/17 上午9:26
 */
public class DemoConsumer {
      public static void main(String[] args) {
          com.alibaba.dubbo.container.Main.main(args);
      }
}

执行main方法启动,看到以下日志输出时,msa-demo-consumer启动成功:

☆聊聊Dubbo(二):简单入门_第7张图片
msa-demo-consumer启动成功

同时服务端会输出服务调用日志信息,并调用成功,如下:

☆聊聊Dubbo(二):简单入门_第8张图片
服务端调用日志

4. 规范使用

模块 描述 是否必须
msa-xxx-api 定义接口&实体 必须
msa-xxx-provider 依赖api模块,实现服务接口,提供服务 必须
msa-xxx-client 依赖api模块,Spring配置文件&测试用例,提供给第三方调用服务使用 必须
msa-xxx-consumer 依赖client模块,建议保留该模块,避免client模块直接与应用方紧耦合 可选

5. 推荐阅读

5.1 Dubbox相关资源

  1. 源码地址 : https://github.com/dangdangdotcom/dubbox
  2. 在Dubbo中开发REST风格的远程调用 : https://dangdangdotcom.github.io/dubbox/rest.html
  3. 在Dubbo中使用高效的Java序列化 : https://dangdangdotcom.github.io/dubbox/serialization.html
  4. 使用JavaConfig方式配置dubbox : https://dangdangdotcom.github.io/dubbox/java-config.html
  5. Dubbo Jackson序列化使用说明 : https://dangdangdotcom.github.io/dubbox/jackson.html
  6. Demo : https://dangdangdotcom.github.io/dubbox/demo.html
  7. 当当网开源Dubbox,扩展Dubbo服务框架支持REST风格远程调用 : http://www.infoq.com/cn/news/2014/10/dubbox-open-source
  8. Dubbox Wiki : https://github.com/dangdangdotcom/dubbox/wiki

5.2 Dubbo相关资源

  1. 源码地址 : https://github.com/alibaba/dubbo
  2. Dubbo Wiki : https://github.com/alibaba/dubbo/wiki
  3. http://dubbo.io/

你可能感兴趣的:(☆聊聊Dubbo(二):简单入门)