分布式服务框架 dubbo/dubbox 入门示例

dubbo是一个分布式的服务架构,可直接用于生产环境作为SOA服务框架。

官网首页:http://dubbo.io/ ,官方用户指南 http://dubbo.io/User+Guide-zh.htm上面的几张图画得不错,完全可以当做SOA架构的学习资料

淘宝将这个项目开源出来以后,得到了不少同行的支持,包括:

当当网的扩展版本dubbox :https://github.com/dangdangdotcom/dubbox

京东的扩展版本jd-hydra: http://www.oschina.net/p/jd-hydra

不过,略有遗憾的是,据说在淘宝内部,dubbo由于跟淘宝另一个类似的框架HSF(非开源)有竞争关系,导致dubbo团队已经解散(参见http://www.oschina.net/news/55059/druid-1-0-9 中的评论),反到是当当网的扩展版本仍在持续发展,墙内开花墙外香。

不管如何,能在阿里、当当、京东这些大型网站正式使用的框架,总不至于差到哪里去。

本文下面的示例均基于当当的dubbox版本,由于dubbox并没向maven提交编译后的jar包,所以只能从github clone代码到本地编译得到jar包。

编译及测试步骤:(以下步骤全在windows环境中完成)

1. 本机先安装github on Windows的客户端,将在path路径中,把git.exe加进去

2. 命令行下 git clone https://github.com/dangdangdotcom/dubbox 把代码拉到本地

3. mvn install -Dmaven.test.skip=true 跳过测试编译

4. 在本机安装一个zookeeper,参考zoo.cfg如下:

tickTime=2000
initLimit=10
syncLimit=5
dataDir=D:/java/zookeeper-3.4.6/data
dataLogDir=D:/java/zookeeper-3.4.6/log
clientPort=2181
server.1=localhost:2287:3387

然后输入 bin/zkServer.cmd 启用zookeeper

5. intellij Idea中导入源码

6. 运行 dubboxdubbo-demodubbo-demo-providersrc estjavacomalibabadubbodemoproviderDemoProvider.java 

把服务提供方跑起来,成功后,可以在ZK里,用 ls / 看下,会发现zk里多出了一个dubbo的节点,所有服务全注册在这里了

7. 运行dubboxdubbo-demodubbo-demo-consumersrc estjavacomalibabadubbodemoconsumerDemoConsumer.java

服务消费方调用测试,可以看console里的输出

8. 运行dubboxdubbo-demodubbo-demo-consumersrc estjavacomalibabadubbodemoconsumerRestClient.java

跑一下rest调用

9. 浏览器访问 http://localhost:8888/services/users/100.xml 或 http://localhost:8888/services/users/100.json

dubbox官方的示例,虽然已经很简单了,但是对于初次接触的人来讲,仍然略显复杂,下面的代码在其基础上简化了一下:

一、先定义服务接口及传输对象DTO

项目结构如下

代码:

User.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package yjmyzz.dubbo.demo.api;
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;
 
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class User implements Serializable {
 
    @NotNull
    @Min(1L)
    private Long id;
 
    @JsonProperty("username")
    @XmlElement(name = "username")
    @NotNull
    @Size(min = 6, max = 50)
    private String name;
 
    public User() {
    }
 
    public User(Long id, String name) {
        this.id = id;
        this.name = name;
    }
 
    public Long getId() {
        return id;
    }
 
    public void setId(Long id) {
        this.id = id;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    @Override
    public String toString() {
        return "User (" +
                "id=" + id +
                ", name='" + name + ''' +
                ')';
    }
}

UserService.java

1
2
3
4
5
package yjmyzz.dubbo.demo.api;
 
public interface UserService {
    User getUser(Long id);
}

UserRestService.java

1
2
3
4
5
6
7
package yjmyzz.dubbo.demo.api;
 
import javax.validation.constraints.Min;
 
public interface UserRestService {
    User getUser(@Min(value = 1L, message = "User ID must be greater than 1") Long id);
}

pom.xml

复制代码
 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0"
 3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 5 
 6     <modelVersion>4.0.0</modelVersion>
 7 
 8     <groupId>com.cnblogs.yjmyzz</groupId>
 9     <artifactId>dubbo-hello-api</artifactId>
10     <version>0.1</version>
11 
12     <dependencies>
13 
14         <dependency>
15             <groupId>com.alibaba</groupId>
16             <artifactId>dubbo</artifactId>
17             <version>2.8.4</version>
18         </dependency>
19 
20         <dependency>
21             <groupId>javax.validation</groupId>
22             <artifactId>validation-api</artifactId>
23             <version>1.0.0.GA</version>
24         </dependency>
25 
26         <dependency>
27             <groupId>javax.annotation</groupId>
28             <artifactId>javax.annotation-api</artifactId>
29             <version>1.2</version>
30         </dependency>
31 
32         <dependency>
33             <groupId>org.codehaus.jackson</groupId>
34             <artifactId>jackson-mapper-asl</artifactId>
35             <version>1.9.12</version>
36         </dependency>
37 
38     </dependencies>
39 </project>
复制代码

二、定义服务生产者(即:服务接口的实现方)

UserServiceImpl.java

1
2
3
4
5
6
7
8
9
10
11
package yjmyzz.dubbo.demo.provider;
 
import yjmyzz.dubbo.demo.api.User;
import yjmyzz.dubbo.demo.api.UserService;
 
public class UserServiceImpl implements UserService {
 
    public User getUser(Long id) {
        return new User(id, "username" + id);
    }
}

UserRestServiceImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package yjmyzz.dubbo.demo.provider;
 
import com.alibaba.dubbo.rpc.RpcContext;
import com.alibaba.dubbo.rpc.protocol.rest.support.ContentType;
import yjmyzz.dubbo.demo.api.User;
import yjmyzz.dubbo.demo.api.UserRestService;
import yjmyzz.dubbo.demo.api.UserService;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
 
@Path("users")
@Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})
@Produces({ContentType.APPLICATION_JSON_UTF_8, ContentType.TEXT_XML_UTF_8})
public class UserRestServiceImpl implements UserRestService {
 
    private UserService userService;
 
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
 
    @GET
    @Path("{id : \d+}")
    public User getUser(@PathParam("id") Long id) {
        if (RpcContext.getContext().getRequest(HttpServletRequest.class) != null) {
            System.out.println("Client IP address from RpcContext: " + RpcContext.getContext().getRequest(HttpServletRequest.class).getRemoteAddr());
        }
        if (RpcContext.getContext().getResponse(HttpServletResponse.class) != null) {
            System.out.println("Response object from RpcContext: " + RpcContext.getContext().getResponse(HttpServletResponse.class));
        }
        return userService.getUser(id);
    }
}

DemoProvider.java

1
2
3
4
5
6
7
8
9
10
11
12
package yjmyzz.dubbo.demo.provider;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
 
public class DemoProvider {
    public static void main(String[] args) throws IOException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath*:META-INF/spring/*.xml");
        context.start();
        System.out.println("服务已经启动...");
        System.in.read();
    }
}

配置文件:resourcesMETA-INFspringdubbo-demo-provider.xml

按 Ctrl+C 复制代码
按 Ctrl+C 复制代码

pom.xml

按 Ctrl+C 复制代码
按 Ctrl+C 复制代码

测试时,运行DemoProvider中的main方法即可启动服务,所有服务注册在ZooKeeper,层次结构类似下面这样:

复制代码
/dubbo
  /dubbo/yjmyzz.dubbo.demo.api.UserRestService
    /dubbo/yjmyzz.dubbo.demo.api.UserRestService/providers
    /dubbo/yjmyzz.dubbo.demo.api.UserRestService/configurators
  /dubbo/yjmyzz.dubbo.demo.api.UserService
    /dubbo/yjmyzz.dubbo.demo.api.UserService/providers
    /dubbo/yjmyzz.dubbo.demo.api.UserService/configurators
复制代码

三、服务消费方

 

DemoConsumer.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package yjmyzz.dubbo.demo.consumer;
 
import org.springframework.context.support.ClassPathXmlApplicationContext;
import yjmyzz.dubbo.demo.api.UserService;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
 
public class DemoConsumer {
 
    public static void main(String[] args) {
        final String port = "8888";
 
        //测试Rest服务
        getUser("http://localhost:" + port + "/services/users/1.json");
        getUser("http://localhost:" + port + "/services/users/1.xml");
 
        //测试常规服务
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath*:META-INF/spring/*.xml");
        context.start();
        UserService userService = context.getBean(UserService.class);
        System.out.println(userService.getUser(1L));
    }
 
 
    private static void getUser(String url) {
        System.out.println("Getting user via " + url);
        Client client = ClientBuilder.newClient();
        WebTarget target = client.target(url);
        Response response = target.request().get();
        try {
            if (response.getStatus() != 200) {
                throw new RuntimeException("Failed with HTTP error code : " + response.getStatus());
            }
            System.out.println("Successfully got result: " + response.readEntity(String.class));
        finally {
            response.close();
            client.close();
        }
    }
}

配置文件:resourcesMETA-INFspringdubbo-hello-consumer.xml

复制代码
 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
 5        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
 6     http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
 7 
 8     <dubbo:application name="demo-consumer" owner="programmer" organization="dubbox"/>
 9 
10     <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
11 
12     <dubbo:reference id="userRestService" interface="yjmyzz.dubbo.demo.api.UserRestService"/>
13 
14     <dubbo:reference id="userService" interface="yjmyzz.dubbo.demo.api.UserService"/>
15 
16 </beans>
复制代码

pom.xml

按 Ctrl+C 复制代码
按 Ctrl+C 复制代码

其它注意事项:

dubbo构架中,zk充着“服务注册中心”的角色,所以生产者与消费者的xml配置文件中,都要配置zk地址,如果zk采用集群部署时,配置写法参考下面这样:

<dubbo:registry address="zookeeper://172.28.*.102:2181?backup=172.28.*.102:2182,172.28.*.102:2183"/>

dubbo还有一个管理界面,用于服务治理,包括启用/禁用服务,设置服务的路由规则(即:A地址的Consumer直接调用B机器的Provider,而不是由负载均衡算法分配)等等。

使用方法:将dubbo-admin这个项目编译成war包后,部署到jetty或其它兼容web server即可(当然要修改WEB-INFdubbo.properties里zk的地址)

部署完成后,访问管理界面时,默认用户名,密码均是root。 

另外dubbo-monitor项目用于性能监控,结合监控产生的数据,再套上一些图表展示的框架,可以用图表方式直观展示各种指标。

注:官网给出的dubbo-admin采用的webx架构有点老,而且除了淘宝之外,几乎没人在用,dubbo-monitor-simple界面也比较古朴,所以社区也人对其做了扩展,详情参考另一篇博客dubbox 的各种管理和监管

2016-02-25:dubbox依赖的spring虽然升级成3.x了,但版本还是有点低,spring都已经4.x了,为了方便我fork了一份,升级成spring 4.x 同时增加了log4j2的日志组件支持,详情见:dubbox升级spring到4.x及添加log4j2支持

参考文章:

http://shiyanjun.cn/archives/341.html

http://blog.csdn.net/wilsonke/article/details/39896595

http://www.dataguru.cn/thread-464197-1-1.html

http://www.iteye.com/magazines/103

http://dangdangdotcom.github.io/dubbox/rest.html

http://dangdangdotcom.github.io/dubbox/demo.html

http://blog.csdn.net/hzzhoushaoyu/article/details/43273099

 
原文地址:https://www.cnblogs.com/smallfa/p/12327554.html