spring boot 整合 dubbo 实战

分布式微服务应用开发应该是当前最为普遍的服务框架了吧,比如HSF、Dubbo以及spring cloud等。由于公司项目使用的就是HSF服务,为了雨露均沾,就闲暇时间,先研究了下Dubbo框架。
Dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。

1.dubbo原理

在进行dubbo项目开发之前我们先来了解下dubbo的工作原理。下面这张图来自dubbo官方文档的首页:http://dubbo.apache.org/zh-cn/index.html
在这里插入图片描述
首先我们先介绍下dubbo的几个关键词:
Container:dubbo服务运行容器,整个dubbo服务都是在这个容器内进行的,你可以理解为web服务必须依赖于servlet容器一样;
Provider:服务提供者,暴露服务的一方称之为服务提供者;
Consumer:服务消费者,调用远程服务的一方称之为服务消费者;
Registry:dubbo注册中心,为服务提供者和消费者提供的一个平台;
Monitor:dubbo监控中心,统计服务的调用次数和调用时间的日志服务;

上面几个的关系其实在我们生活中随处可见的,举个我自认为很贴切的例子:我们整个网络环境相当于dubbo容器,商家相当于服务提供者,买家相当于服务消费者,淘宝这个平台相当于注册中心,商家将商品在淘宝展示相当于服务提供者向注册中心注册服务,买家将商品添加到购物车则可以比作为服务消费者订阅服务,结账付款则是服务消费者调用服务提供者提供的服务,其中监控中心可以看作是淘宝的我的订单功能,通过监控中心,你可以看到服务提供者和消费者的行为。

结合上面的图我们在分析一波dubbo工作原理:dubbo容器启动[0.start],服务提供者向dubbo的注册中心注册服务[1.register],服务消费者则从dubbo的注册中心订阅服务[2.subscribe],0/1/2这三步我们可以看到是用紫色虚线勾画的,表示的是dubbo服务初始化的过程;当服务提供者发生变化后注册中心会通知服务消费者[3.notify],这一步是用蓝色虚线勾画的,表示的是dubbo的异步过程;服务消费者订阅服务后就可以调用服务提供者提供的服务[4.invoke],这一步是用蓝色实线勾画的,表示的是dubbo的实时调用过程;服务提供者和消费者的行为都会被dubbo监控中心监控[5.count],这一步也是用蓝色虚线勾画的,同样表示的是异步进行的过程。

了解了dubbo整个工作原理后,那么我们就一起开始开发一个简单的dubbo工程吧!

2.安装dubbo注册中心

俗话说的好:工欲善其事必先利其器。在码代码之前我们需要安装下dubbo的注册中心并启动dubbo容器。
这里我们选择官方推荐的注册中心zookeeper:http://archive.apache.org/dist/zookeeper/

2.1第一步选择下载对应版本的压缩包:

在这里插入图片描述
在这里插入图片描述

2.2第二步减压到自定义目录即可:

在这里插入图片描述

2.3第三步编写配置文件

zookeeper的配置文件需要我们自己编写,当然它为我们提供了一个模板:即在conf目录下的zoo_sample.cfg文件。在这里插入图片描述
我们只需要简单copy一份并命名为zoo.cfg即可。
在这里插入图片描述

2.4第四步修改配置文件

zoo.cfg配置文件中我们只需要关心zookeeper的端口为2181,并修改zookeeper的数据保存位置即可,这个目录在启动时会自动生成。
在这里插入图片描述

3.启动zookeeper

接下来我们就可以启动dubbo了,我们需要在bin目录下运行zkServer.cmd脚本。
在这里插入图片描述
进入doc窗口后输入zkServer.cmd后回车即可。
在这里插入图片描述
在这里插入图片描述
启动结果:
在这里插入图片描述

4.码代码

接下来就来到我们期待已久的环节了:编写代码!!!

4.1项目整体框架

在这里插入图片描述
上图就是我们整个项目的模块架构:
springBootDubboParent:项目的父工程,父工程主要是集成我们的子模块,没有编写其他业务代码,下面是它的pom文件:

<?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 https://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.3.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.springboot.dubbo</groupId>
    <artifactId>dubbo.springBootDubboParent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springBootDubboParent</name>
    <packaging>pom</packaging>
    <modules>
        <module>dubboServiceCommon</module>
        <module>userServiceProvider</module>
        <module>orderServiceConsumer</module>
    </modules>
    <properties>
        <java.version>11</java.version>
    </properties>

</project>

4.2公共模块

dubboServiceCommon:项目的公共模块,主要包含了我们自定义的bean对象和接口的定义,该模块的作用就是将我们的实体类和接口类统一定义封装然后以jar包的形式导入需要依赖的模块中,实现代码的复用。
在这里插入图片描述
pom文件

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.springboot.dubbo</groupId>
        <artifactId>dubbo.springBootDubboParent</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <artifactId>dubbo.dubboServiceCommon</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>dubboServiceCommon</name>

    <properties>
        <java.version>11</java.version>
    </properties>

</project>

UserAddress:
定义一个用户地址实体类,主要包括用户id和地址信息

package com.bean;

import java.io.Serializable;

public class UserAddress implements Serializable {

    private Integer id;
    private String userAddress;  //用户地址
    private String userId;   //用户id
    private String userName; //用户名字
    private String phoneNum; //用户电话
    private String isDefault; //是否默认收获地址 Y - 是 N - 否

    public UserAddress(Integer id, String userAddress, String userId, String userName, String phoneNum, String isDefault) {
        this.id = id;
        this.userAddress = userAddress;
        this.userId = userId;
        this.userName = userName;
        this.phoneNum = phoneNum;
        this.isDefault = isDefault;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUserAddress() {
        return userAddress;
    }

    public void setUserAddress(String userAddress) {
        this.userAddress = userAddress;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPhoneNum() {
        return phoneNum;
    }

    public void setPhoneNum(String phoneNum) {
        this.phoneNum = phoneNum;
    }

    public String getIsDefault() {
        return isDefault;
    }

    public void setIsDefault(String isDefault) {
        this.isDefault = isDefault;
    }

    @Override
    public String toString() {
        return "UserAddress{" +
                "id=" + id +
                ", userAddress='" + userAddress + '\'' +
                ", userId='" + userId + '\'' +
                ", userName='" + userName + '\'' +
                ", phoneNum='" + phoneNum + '\'' +
                ", isDefault='" + isDefault + '\'' +
                '}';
    }
}

OrderService:
定义一个订单服务接口,根据用户id获取其所有的地址信息

package com.service.order;

import com.bean.UserAddress;

import java.util.List;

/**
 * 订单服务
 */
public interface OrderService {

    /**
     * 根据用户id 初始化 订单
     * @param userId
     */
    public List<UserAddress> initOrder(String userId);
}

UserService:
定义一个用户服务接口,实现查询用户所有地址的功能

package com.service.user;



import com.bean.UserAddress;

import java.util.List;

/**
 * 用户服务
 */
public interface UserService {

    /**
     * 根据用户id返回用户所有的收获地址
     * @param userId
     * @return
     */
    public List<UserAddress> qryUserAddressList(String userId);
}

4.3服务提供者模块

在userServiceProvider这个模块中编写我们的服务提供者,并实现与dubbo的整合。

A.服务提供者想要在dubbo的注册中心注册服务,暴露服务给消费者,需要分以下几步进行:
1.指定dubbo注册中心的位置两种方式
dubbo.registry.address=zookeeper://10.20.153.10:2181
或者
dubbo.registry.address=127.0.0.1:2181 dubbo.registry.protocol=zookeeper
2.由于dubbo属于RPC的一种,所以需要指定通信协议
dubbo.protocol.name=dubbo //采用dubbo协议
dubbo.protocol.port=20880 //端口为20880
3.配置监控中心,从注册中心自动监听服务
dubbo.monitor.protocol=registry
4.指定当前服务(应用)的名字
dubbo.application.name=userServiceProvider
以上就是配置文件的所有配置[最小配置]
B.接下来需要使用dubbo的@Service注解暴露我们的服务提供者
注意:是导入dubbo的service:
import com.alibaba.dubbo.config.annotation.Service
C.在启动类使用注解@EnableDubbo开启dubbo功能
自此关于服务提供者的最小配置全部完毕,源码都有注释[注释是一个优秀程序员自我修养的标记]

在这里插入图片描述
pom文件

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.springboot.dubbo</groupId>
        <artifactId>dubbo.springBootDubboParent</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>dubbo.userServiceProvider</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>userServiceProvider</name>

    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.springboot.dubbo</groupId>
            <artifactId>dubbo.dubboServiceCommon</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

        <!--引入spring-boot集成dubbo-->
        <dependency>
            <groupId>com.alibaba.boot</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>0.2.1.RELEASE</version>
         </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>RELEASE</version>
        </dependency>

        <!--NoClassDefFoundError: io/netty/bootstrap/ServerBootstrap-->
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
        </dependency>


        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.73</version>
        </dependency>

        <!--Caused by: java.lang.ClassNotFoundException: org.apache.curator.framework.CuratorFrameworkFactory-->
        <!-- https://mvnrepository.com/artifact/org.apache.curator/curator-recipes -->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>2.13.0</version>
        </dependency>

        <!--日志-->
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-mapper-asl</artifactId>
            <version>1.9.4</version>
            <exclusions>
                <exclusion>
                    <groupId>com.alibaba</groupId>
                    <artifactId>fastjson</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

UserServiceImpl

package com.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.bean.UserAddress;
import com.service.user.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

/**
 * 1.将服务提供者注册到注册中心(暴露服务)
 *      a.导入sringboot-dubbo依赖及其他dubbo依赖
 *      b.配置服务提供者
 * 2.让服务消费者到注册中心订阅服务提供者的服务地址
 *
 */
@Service   //应该引入dubbo的service,暴露服务,通过该注解将该服务注册中注册中心
@Component //springboot 组件 因为要引入dubbo的service注解,所以spring的service不能用了,只能引入Component
public class UserServiceImpl implements UserService {

    private final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    public List<UserAddress> qryUserAddressList(String userId) {
        logger.info("Begin call UserServiceImpl qryUserAddressList method  and request params{} " , JSON.toJSONString(userId));
        UserAddress userAddress1 = new UserAddress(
                1,
                "北京大兴区经开大厦",
                "10001",
                "Tom",
                "18402021042",
                "N"
        );
        UserAddress userAddress2 = new UserAddress(
                2,
                "北京大兴区大雄郁金香",
                "10001",
                "Tom",
                "18402021042",
                "Y"
        );
        List<UserAddress> userAddresses = Arrays.asList(userAddress1, userAddress2);
        System.out.println(userAddresses);
        return userAddresses;
    }
}

application.properties

#启动报错
spring.main.allow-bean-definition-overriding=true
#duboo配置
#指定当前服务(应用)的名字,区别于其他服务
dubbo.application.name=userServiceProvider

#指定注册中心的位置
dubbo.registry.address=127.0.0.1:2181
dubbo.registry.protocol=zookeeper

#指定通信规则:通信协议+通信端口
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880

#监控中心从注册中心自动监听服务
dubbo.monitor.protocol=registry

4.4服务消费者模块

在orderServiceConsumer这个模块中编写我们的服务消费者,并实现与dubbo的整合。

服务消费者想要实现订阅并消费服务,分以下几步进行:
1.dubbo配置文件[基本和提供者的配置一样]
a.指定当前服务(应用)的名字
dubbo.application.name=orderServiceConsumer
b.指定注册中心的位置
dubbo.registry.address=zookeeper://127.0.0.1:2181
c.监控中心从注册中心自动监听服务
dubbo.monitor.protocol=registry
申明调用哪个服务的提供者通过注解实现@Reference,所以不需要在配置文件里配置
2.使用dubbo的@Reference注解从注册中心发现并订阅指定的服务提供者
3.在启动类使用注解@EnableDubbo开启dubbo功能

在这里插入图片描述
pom文件

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.springboot.dubbo</groupId>
        <artifactId>dubbo.springBootDubboParent</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <artifactId>dubbo.orderServiceConsumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>orderServiceConsumer</name>

    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>com.springboot.dubbo</groupId>
            <artifactId>dubbo.dubboServiceCommon</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <!--引入spring-boot集成dubbo-->
        <dependency>
            <groupId>com.alibaba.boot</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>0.2.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.6.5</version>
            <scope>compile</scope>
        </dependency>

        <!--Caused by: java.lang.ClassNotFoundException: org.apache.curator.framework.CuratorFrameworkFactory-->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>2.13.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

OrderServiceImpl

package com.service.impl;


import com.alibaba.dubbo.config.annotation.Reference;
import com.bean.UserAddress;
import com.service.order.OrderService;
import com.service.user.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 1.将服务提供者注册到注册中心
 *      a.导入spring boot - dubbo依赖
 *      b。引入dubbo其他依赖
 * 2.让服务消费者到注册中心订阅服务提供者的服务地址
 *
 */
@Service   //应该引入dubbo的service,如果不是作为服务提供者向注册中心注册服务,那么service注解可以使用spring的注解
@Component //springboot 组件
public class OrderServiceImpl implements OrderService {

    //@Autowired
    @Reference //通过dubbo的该注解从注册中心发现并订阅服务
    private UserService userService;

    public List<UserAddress> initOrder(String userId) {

        List<UserAddress> userAddressList = userService.qryUserAddressList(userId);
        return userAddressList;
    }
}

OrderController

package com.controller;

import com.bean.UserAddress;
import com.service.order.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class OrderController {

    @Autowired
    private OrderService orderService;
    
    @GetMapping("/initOrder")
    public List<UserAddress> initOrder(@RequestParam(value = "userId",required = true) String userId) {
        List<UserAddress> userAddresses = orderService.initOrder(userId);
        return userAddresses;
    }
}

application.properties

#由于该工程是war包,所以启动会使用tomcat的默认8080端口,而监控中心monitor的端口也是8080
#修改tomcat的端口为8081
server.port=8081


#duboo配置
#指定当前服务(应用)的名字,区别于其他服务
dubbo.application.name=orderServiceConsumer

#指定注册中心的位置,两种方式
dubbo.registry.address=zookeeper://127.0.0.1:2181

#监控中心从注册中心自动监听服务
dubbo.monitor.protocol=registry

#申明调用哪个服务的提供者通过注解@Reference实现,所以不需要在配置文件里配置

5.启动项目

5.1启动zookeeper注册中心

在这里插入图片描述

5.2启动服务提供者

在这里插入图片描述

5.3启动服务消费者

在这里插入图片描述

5.4测试

通过消费者暴露的端口访问我们的controller层,返回的数据是后台模拟的虚假数据。

http://127.0.0.1:8081/initOrder?userId=1

在这里插入图片描述

6.官方文档

http://dubbo.apache.org/zh-cn/docs/user/quick-start.html
上面只是简单的搭建了一个dubbo工程,dubbo还有很多知识点需要去探索,比如负载均衡,服务降级,服务超时以及dubbo的多种配置形式等等。大家可以通过上面的官方链接进行更深入的了解,里面每个知识点都有很详细的讲解以及示例。
我会把我的demo分享给大家,这样你们就可以基于这个demo进行扩展测试其他dubbo功能了,需要源码得小伙伴可以私信我。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值