Springboot dubbo zookeeper 实现简单的注册后台搭建

这几天工作没什么事,学习下Springboot dubbo zookeeper

:介绍下学习内容:

1:zookeeper做服务注册和管理中心
2:dubbo服务调度
3:mybatis、springboot集成
总的来说就是通过这套框架实现了一个简单的注册demo(这里不强调注册逻辑中的细节)

zookeeper安装及部署

环境:CentOS7、zookeeper:3.4.14(没有用zookeeper的最新版,因为集群部署的时候有个奇怪的坑)、docker。
现在只要是部署啊,安装啊什么的很多情况下都是docker安装了,这里废话不多,直接上zookeeper的部署流程

1:在usr/local下创建docker文件夹,再在下面创建zookeeper文件夹

/usr/local/docker/zookeeper

2:创建docker-compose.yml文件

vi docker-compose.yml
#以下是配置文件

services:
zoo1:
    image: zookeeper:3.4.14
    restart: always
    hostname: zoo1
    ports:
        - 2182:2181
    environment:
        ZOO_MY_ID: 1
        ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888

zoo2:
    image: zookeeper:3.4.14
    restart: always
    hostname: zoo2
    ports:
        - 2183:2181
    environment:
        ZOO_MY_ID: 2
        ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888

zoo3:
    image: zookeeper:3.4.14
    restart: always
    hostname: zoo3
    ports:
        - 2184:2181
    environment:
        ZOO_MY_ID: 3
        ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888

配置好了记住保存,千万记住wq,还有版本最好不要省去,可能会出现集群安装失败的问题!保存后启动,在当前文件夹下(与docker-compose.yml同级)

docker-compose up -d

启动后看下启动成功没有,启动成功了后随便进入一个容器去查看下集群模式启动成功没有

查看容器

docker ps

交互模式进入容器查看(这里应该有三个zookeeper的容器启动了,可以随便进入一个去查看,这里进入的是第三个)

docker exec -it zookeeper_zoo3_1 /bin/bash
#然后检查启动状态
./bin/zkServer.sh status

如果出现以下表示集群启动成功了,进入其他两个查看状态的话Mode应follower,表示我们zookeeper以及配置并且启动好了

root@zoo3:/zookeeper-3.4.14# ./bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /conf/zoo.cfg
Mode: leader

向dubbo暴露服务接口

首先创建一个maven项目(官方例子是将服务接口,服务实现(provider),服务调用(consumer))三个单独分开来做的,没有一个统一的pom来管理,我多了一步是先创建了一个统一的包来管理这接口、提供、消费)
Springboot dubbo zookeeper 实现简单的注册后台搭建_第1张图片
这里的demoPom就是一个最简单的一个maven项目包,在pom.xml中加入打包类型就可以了因为这个只用起到管理作用,所以src目录没有什么用了,直接删除即可

pom

创建完成后在包中新建module
Springboot dubbo zookeeper 实现简单的注册后台搭建_第2张图片
Springboot dubbo zookeeper 实现简单的注册后台搭建_第3张图片
依然是创建一个maven项目这个模块只提供接口,版本号建议与项目的版本号相同,其他没有多余的设置,直接下一步下一步就完事儿了
创建完成后这个接口模块中的pom.xml需要添加

jar

注:需要去看看demoPom中的pom.xml是否自动添加了
Springboot dubbo zookeeper 实现简单的注册后台搭建_第4张图片
如果没有自动添加的话,需要自己手动添加自己创建模块的artifactId
这是我本例子中的接口模块的目录结构
Springboot dubbo zookeeper 实现简单的注册后台搭建_第5张图片
在api包中定义了一个interface:

package com.kj.demopom.user.api;

import com.kj.demopom.user.domain.User;

public interface RegistUser {
     
    int registUser(User user);      //用户注册
    boolean flagUser(String name);  //因为数据库name字段设置了主键,所以要判断数据库有没有相同的name值
}

domain中是一个user的实体类(必须要实现序列化接口):

package com.kj.demopom.user.domain;

import java.io.Serializable;

public class User implements Serializable {
     
    private String name;
    private String password;
    private String old;

    public String getPassword() {
     
        return password;
    }

    public void setPassword(String password) {
     
        this.password = password;
    }

    public String getOld() {
     
        return old;
    }

    public void setOld(String old) {
     
        this.old = old;
    }

    public String getName() {
     
        return name;
    }

    public void setName(String name) {
     
        this.name = name;
    }

    @Override
    public String toString() {
     
        return "User{" +
                "name='" + name + '\'' +
                ", password='" + password + '\'' +
                ", old='" + old + '\'' +
                '}';
    }
}

接口和实体类定义好了,首先我们先clean打包了,用maven自带的打包工具就可以啦啦,或者
Springboot dubbo zookeeper 实现简单的注册后台搭建_第6张图片
运行下就可以了,提示build success表示成功了
Springboot dubbo zookeeper 实现简单的注册后台搭建_第7张图片
或者直接控制台 mvn clean install,进行build,build成功后要刷新一下maven

构建服务提供模块(provider)

还是先在再创建一个模块,这次不是创建maven项目了。创建一个Spring Initializr模块啦。
Springboot dubbo zookeeper 实现简单的注册后台搭建_第8张图片
项目名这些搞完了过后选择依赖的时候可以不用选择,因为这个是提供服务的(要实现接口,方便其他服务调用),所以不是web项目,其他的依赖看你自己,也可以什么都不选择。
Springboot dubbo zookeeper 实现简单的注册后台搭建_第9张图片

然后next后选一下目录然后就完成了,第一次构建可能有点慢,需要等等。

1:添加依赖

spring dubbo:
		<dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-actuatorartifactId>
        dependency>
        <dependency>
            <groupId>com.alibaba.bootgroupId>
            <artifactId>dubbo-spring-boot-starterartifactId>
            <version>0.2.0version>
        dependency>

mysql mybatis:

		<dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <scope>runtimescope>
        dependency>
        <dependency>
            <groupId>org.mybatis.spring.bootgroupId>
            <artifactId>mybatis-spring-boot-starterartifactId>
            <version>1.3.0version>
        dependency>

自己的接口(接口在本地没有上传服务器,如果报错肯定是clean时没有成功):

		<dependency>
            <groupId>com.kjgroupId>
            <artifactId>demoPom-user-apiartifactId>
            <version>1.0-SNAPSHOTversion>
        dependency>

以上依赖就是本例子用到的依赖。
2:配置文件:
全部采用yml文件配置(有些地方打了***,基本上看的出来是什么,不是骂人哈,嘻嘻)

spring:
  application:
    name: demopom-user-provider
  datasource:
    url: jdbc:mysql://localhost:3306/demoPom?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT
    username: root
    password: ********
    driver-class-name: com.mysql.jdbc.Driver

mybatis:
  mapper-locations: classpath:mapper/*.xml

user:
  service:
    version: 1.0.0
dubbo:
  scan:
    basePackages: com.kj.demopom.user.provider.api.impl
  application:
    id: demopom-user-provider
    name: demopom-user-provider
  registry:
    id: zookeeper
    address: zookeeper://1**.1**.**.1**:2182?backup=1**.1**.**.1**:2183,1**.1**.**.1**:2184

配置完成后,就可以开心的写代码了。(注册中心zookeeper的主机ip和端口,一定要看准啊)。
以下是provider这个服务的结构,简单解释一下:
1、comment里面放的是常量类,放一些常量
2、mapper,就不用多说了,mybatis的接口
3、service下有两个包,第一个包里面的RegistUserImpl是实现了自己定义的接口,RegistUserFunctionApi是为了实现RegistUserImpl中的一些方法而定义的接口,RegistUserFunctionApiImpl是对这个接口的实现Springboot dubbo zookeeper 实现简单的注册后台搭建_第10张图片
上代码:
StatusArgs.java

package com.kj.demopom.user.provider.api.impl.comment;
public class StatusArgs {
     
    public static final int Flag_User_SUCCESS = 0;    //验证成功,不存在当前name
    public static final int Flag_User_FAILED = 1;    //验证失败,存在当前name
}

RegistUserFunctionMapper.java

package com.kj.demopom.user.provider.api.impl.mapper;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

@Mapper
@Repository
public interface RegistUserFunctionMapper {
     
    //查询数据库中存在当前name吗
    int RegistFlagUser(String name);
    //添加用户
    int RegistUserIntsert(@Param("name") String name,
                          @Param("password") String password,
                          @Param("old") String old);
}

RegistUserImpl.java

package com.kj.demopom.user.provider.api.impl.service.apiIpml;


import com.alibaba.dubbo.config.annotation.Service;
import com.kj.demopom.user.api.RegistUser;
import com.kj.demopom.user.domain.User;
import com.kj.demopom.user.provider.api.impl.service.RegistUserFunctionApi;
import com.kj.demopom.user.provider.api.impl.comment.StatusArgs;
import org.springframework.beans.factory.annotation.Autowired;


@Service(version = "1.0.1")
public class RegistUserImpl implements RegistUser {
     

    private boolean flagBLN;	//用于接收查询name结果的参数
    private int registUserIntsert = 0;	//判断保存用户成功的参数
    @Autowired
    private RegistUserFunctionApi registUserFunctionApi;

    @Override
    public int registUser(User user) {
     
        flagBLN = flagUser(user.getName());
        if (flagBLN){
     	//如果name的判断通过,即不存在当前name执行insert
            registUserIntsert = registUserFunctionApi.RegistUserIntsert(user);
        }
        return registUserIntsert;
    }

    @Override
    public boolean flagUser(String name) {
     
    	
        int flagNum = registUserFunctionApi.RegistFlagUser(name);//查询name
        flagBLN = flagNum == StatusArgs.Flag_User_SUCCESS;
        return flagBLN;
    }
}

RegistUserFunctionApi.java

package com.kj.demopom.user.provider.api.impl.service;

import com.kj.demopom.user.domain.User;

public interface RegistUserFunctionApi {
     
    public int RegistFlagUser(String name);
    public int RegistUserIntsert(User user);
}

RegistUserFunctionApiImpl.java

package com.kj.demopom.user.provider.api.impl.service.Impl;

import com.kj.demopom.user.domain.User;
import com.kj.demopom.user.provider.api.impl.comment.StatusArgs;
import com.kj.demopom.user.provider.api.impl.mapper.RegistUserFunctionMapper;
import com.kj.demopom.user.provider.api.impl.service.RegistUserFunctionApi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class RegistUserFunctionApiImpl implements RegistUserFunctionApi {
     
    @Autowired
    private RegistUserFunctionMapper registUserFunctionMapper;
    @Override
    public int RegistFlagUser(String name) {
     
        int flagUser = registUserFunctionMapper.RegistFlagUser(name);
        //查询name后返回值不等于0就等于1,用于判断
        if (flagUser != StatusArgs.Flag_User_SUCCESS){
     
            flagUser = StatusArgs.Flag_User_FAILED;
        }
        return flagUser;
    }

    @Override
    public int RegistUserIntsert(User user) {
     
        return registUserFunctionMapper.RegistUserIntsert(user.getName(),user.getPassword(),user.getOld());
    }
}

RegistUserFunctionMapper.xml



<mapper namespace="com.kj.demopom.user.provider.api.impl.mapper.RegistUserFunctionMapper">
    <select id="RegistFlagUser" parameterType="String" resultType="int">
        select count(name) from user u where u.name = #{name}
    select>

    <insert id="RegistUserIntsert" parameterType="String"
            useGeneratedKeys="true" >
        insert into user values(#{name},#{password},#{old})
    insert>
mapper>

到此provider这个模块完成了

构建服务消费模块(consumer)

和provider不一样,这个模块是一个web项目,所以新建的时候选择依赖的时候将Sping Web勾选上在这里插入图片描述
其他的基本一致,
同样需要依赖自己的接口和dubbo,在pom.xml中添加:

		<dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-actuatorartifactId>
        dependency>
        <dependency>
            <groupId>com.alibaba.bootgroupId>
            <artifactId>dubbo-spring-boot-starterartifactId>
            <version>0.2.0version>
        dependency>

自己的接口:

		<dependency>
            <groupId>com.kjgroupId>
            <artifactId>demoPom-user-apiartifactId>
            <version>1.0-SNAPSHOTversion>
        dependency>

如果一开始没有选择web的依赖,需要添加:

 	   <dependency>
           <groupId>org.springframework.bootgroupId>
           <artifactId>spring-boot-starter-thymeleafartifactId>
       dependency>
       <dependency>
           <groupId>org.springframework.bootgroupId>
           <artifactId>spring-boot-starter-webartifactId>
       dependency>

application.yml(除了没有数据库和mybatis的配置其他基本一样):

spring:
 application:
   name: demopom-user-consumer

user:
 service:
   version: 1.0.0
dubbo:
 scan:
   basePackages: com.kj.demopom.user.consumer.controller
 application:
   id: demopom-user-consumer
   name: demopom-user-consumer
 registry:
   id: zookeeper
   address: zookeeper://1**.1**.**.1**:2182?backup=1**.1**.**.1**:2183,1**.1**.**.1**:2184

这是用于测试的三个页面,第一个是失败跳转,第二个是注册页,第三个是成功的页面,
Springboot dubbo zookeeper 实现简单的注册后台搭建_第11张图片
注册页面:


<html lang="zh" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
    <form action="/user/registed" method="post">
        用户名:<input type="text" name="name"><br>
        密码:<input type="text" name="password"><br>
        年龄:<input type="text" name="old"><br>
        <button type="submit">提交button>
    form>
body>
html>

成功页面:


<html lang="zh" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
<h1 th:text="${user.name}">
h1>
body>
html>

页面很简单注册成功转跳并显示当前注册的name参数

模块的结构:
PageName:存放页面的名称的常量类
StatusArgs:存放固定参数的常量类
RegistController:处理业务逻辑,调用接口
RegistService:处理业务逻辑的接口
RegistServiceImpl:实现RegistService接口
Springboot dubbo zookeeper 实现简单的注册后台搭建_第12张图片
代码:
PageName.java

package com.kj.demopom.user.consumer.comment;

public class PageName {
     
    public static final String PAGE_NAME_REGIST = "regist";
    public static final String PAGE_NAME_REGIST_FAILED = "faild";
    public static final String PAGE_NAME_REGIST_SUCCESS = "success";
}

StatusArgs.java

package com.kj.demopom.user.consumer.comment;

public class StatusArgs {
     
    public static final int REGIST_USER_FAILED = 0;
    public static final String USER_PARAM_NAME = "user";
}

RegistController.java

package com.kj.demopom.user.consumer.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.kj.demopom.user.api.RegistUser;
import com.kj.demopom.user.consumer.comment.PageName;
import com.kj.demopom.user.consumer.comment.StatusArgs;
import com.kj.demopom.user.consumer.service.RegistService;
import com.kj.demopom.user.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpSession;

@Component
@Controller
public class RegistController {
     

    @Autowired
    private RegistService registService;

    @Reference(version = "1.0.1")
    private RegistUser registUser;

    @PostConstruct
    public void init(){
     
        //想registService中初始化registUser,
        // 直接在registService中不能直接调用registUser,
        // 会报nullpoint 甚至启动时候报错服务找不到
        registService.setRegistUser(registUser);
    }


    @GetMapping(value = "/user/regist")
    public String showRegist(){
     
        return registService.showRegist();
    }

    @PostMapping(value = "/user/registed")
    public String Registing(User user, HttpSession session){
     
        int registing = registService.Registing(user);
        if (registing == StatusArgs.REGIST_USER_FAILED){
     
            return PageName.PAGE_NAME_REGIST_FAILED;
        }else{
     
            session.setAttribute(StatusArgs.USER_PARAM_NAME,user);
            return PageName.PAGE_NAME_REGIST_SUCCESS;
        }
    }
}

RegistService.java

package com.kj.demopom.user.consumer.service;

import com.kj.demopom.user.api.RegistUser;
import com.kj.demopom.user.domain.User;

public interface RegistService {
     
    String showRegist();
    int Registing(User user);
    void setRegistUser(RegistUser registUser);
}

RegistServiceImpl.java

package com.kj.demopom.user.consumer.service.Impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.kj.demopom.user.api.RegistUser;
import com.kj.demopom.user.consumer.comment.PageName;
import com.kj.demopom.user.consumer.service.RegistService;
import com.kj.demopom.user.domain.User;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;


@Service()
@Component
public class RegistServiceImpl implements RegistService {
     

    int registUser_FLAG;

    @Reference(version = "1.0.1")
    private RegistUser registUser;

    public void setRegistUser(RegistUser registUser) {
     
        this.registUser = registUser;
    }

    @Override
    public String showRegist() {
     
        return PageName.PAGE_NAME_REGIST;
    }

    @Override
    public int Registing(User user) {
     
        System.out.println(user.toString());
        String username = user.getName();
        boolean flagUser = registUser.flagUser(user.getName());
        if (flagUser){
     
            registUser_FLAG = this.registUser.registUser(user);
        }
        return registUser_FLAG;
    }
}

说明下:在Controller中可以直接调用
@Reference(version = “1.0.1”)
private RegistUser registUser;
并且得到接口实例,但是如果是在service中就不能直接得到,本人觉得业务逻辑隐藏起来是比较好的,所以借用Service来调用接口,达到隐蔽的效果,就为什么service中直接得到实例为null,目前我也不清楚,目前能想到的方法是在controller中使用初始化的方式来自动的注入进service。

效果:
启动provider后再启动 consumer,由于没有安装dubbo的admin,所以只能在zookeeper中查看服务同样随便交互进入一个zookeeper中,在bin中启动zkCli.sh 客户端

查看节点:
ls /
查看节点中注册的服务:
ls /节点名

在这里插入图片描述
进入dubbo中查看,可以发现这个服务,表名这个服务以及注册到zookeeper中了
在这里插入图片描述
访问 http://localhost:8080/user/regist/
Springboot dubbo zookeeper 实现简单的注册后台搭建_第13张图片
Springboot dubbo zookeeper 实现简单的注册后台搭建_第14张图片
返回成功结果:
Springboot dubbo zookeeper 实现简单的注册后台搭建_第15张图片
数据库:
Springboot dubbo zookeeper 实现简单的注册后台搭建_第16张图片
说明结果是正确的,通过zookeeper和dubbo成功实现了接口的远程调用。
实现了服务端与消费端的通信

你可能感兴趣的:(dubbo,zookeeper,springboot,dubbo,zookeeper,spring,分布式)