前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringCloud技术指南系列(六)服务注册发现之Zookeeper服务注册

SpringCloud技术指南系列(六)服务注册发现之Zookeeper服务注册

作者头像
品茗IT
发布2019-09-12 09:46:02
1.4K0
发布2019-09-12 09:46:02
举报
文章被收录于专栏:品茗IT品茗IT品茗IT

SpringCloud技术指南系列(六)服务注册发现之Zookeeper服务注册

SpringCloud所谓的服务注册与发现,流程大致是:

  • 将Springboot微服务客户端项目的地址等信息,通过网络发送到注册中心,由注册中心保存下来。
  • 另一个客户端B访问已经注册到注册中心的服务A,通过注册中心提供的域名解析方式,解析出服务A的地址等信息。
  • 如果提供服务A的客户端有多个,就按照某个策略(比如轮询、负载均衡等)选取一个地址返回。
  • 客户端B访问注册中心返回的地址,获取结果,这里注意,是B直接访问A,而不是注册中心转发,因此要保证B和A是互通的。

目前服务发现的解决方案有Eureka,Consul,Zookeeper等,这三个是SpringCloud官方支持的。

前几篇已经讲了如何搭建Eureka的服务注册发现,本篇讲下Consul的服务注册如何实现,下一篇介绍下consul的服务如何调用。

代码可以在SpringBoot组件化构建https://www.pomit.cn/java/spring/springcloud.html中的ZkServer组件中查看,并下载。

**如果大家正在寻找一个java的学习环境,或者在开发中遇到困难,可以<a

href="https://jq.qq.com/?_wv=1027&k=52sgH1J"

target="_blank">

加入我们的java学习圈,点击即可加入

</a>

,共同学习,节约学习时间,减少很多在学习中遇到的难题。**

一、Zookeeper注册中心

Zookeeper可以在Zookeeper官网 查看下载地址。

Web基础配置篇(十一): Zookeeper的安装配置及使用 这篇文章详细介绍了zookeeper的安装使用方法。

假设本篇的zookeeper地址是 localhost:2181.

二、引入依赖

需要引入spring-boot-starter-web和spring-cloud-starter-zookeeper-discovery。

然而,spring-cloud-starter-zookeeper-discovery默认引入的zookeeper是3.5的版本,因此如果你安装的zookeeper是3.4的版本,就必须排除zookeeper的依赖,并引入3.4的版本。

依赖如下:

<?xml version="1.0"?>
<project
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
	xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>cn.pomit</groupId>
		<artifactId>springcloudwork</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>
	<artifactId>ZkServer</artifactId>
	<name>ZkServer</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
		<maven-jar-plugin.version>2.6</maven-jar-plugin.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
			<exclusions>
				<exclusion>
					<groupId>org.apache.zookeeper</groupId>
					<artifactId>zookeeper</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.apache.zookeeper</groupId>
			<artifactId>zookeeper</artifactId>
			<version>3.4.14</version>
			<exclusions>
				<exclusion>
					<groupId>org.slf4j</groupId>
					<artifactId>slf4j-log4j12</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>
</project>

父模块pom文件可以在https://www.pomit.cn/spring/SpringCloudWork/pom.xml获取。

三、配置zookeeper服务注册

这里使用yaml文件写配置,application.yml:

server:
   port: 8811
spring:
   application:
      name: zkServer
   cloud:
      zookeeper:
         connect-string: localhost:2181
         discovery:
            enabled: true

这里面,包含了端口、应用名、zookeeper注册中心信息。

spring.application.name是标识了应用名,注册到zookeeper之后,显示的就是它。

spring.cloud.zookeeper.connect-string是指明了zookeeper的地址端口。

spring.cloud.zookeeper.discovery.enabled 是开启服务注册发现。

四、启动服务注册

3.1 启动类

使用@EnableDiscoveryClient注解启动类, @EnableDiscoveryClient是将项目作为客户端注册到注册中心的注解,开启服务发现功能。

ZkServerApplication :

package cn.pomit.springbootwork.zkserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class ZkServerApplication {
	public static void main(String[] args) {
		SpringApplication.run(ZkServerApplication.class, args);
	}
}
3.2 开放服务

下面提供了个web接口做服务,访问http://127.0.0.1:8858/zkApi/ip ,可以获取当前请求ip和服务器ip地址。由于我们已经使用了zookeeper做注册中心,其他应用已经可以通过服务名找到本应用,并通过服务发现访问http://zkServer/zkApi/ip 来访问改接口(注意,普通http请求这样写是访问不到的,只有通过服务注册发现调用,走zookeeper的域名服务才能这样访问)。

ZkServerRest :

package cn.pomit.springbootwork.zkserver.web;

import javax.servlet.http.HttpServletRequest;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import cn.pomit.springbootwork.zkserver.model.IpModel;
import cn.pomit.springbootwork.zkserver.model.ResultModel;
import cn.pomit.springbootwork.zkserver.util.IPUtil;

@RestController
@RequestMapping("/zkApi")
public class ZkServerRest {

	@RequestMapping(value = "/ip", method = { RequestMethod.GET })
	public ResultModel welCome(HttpServletRequest request) {
		IpModel ipModel = new IpModel();
		ipModel.setClientIpAddress(IPUtil.getIpAddr(request));
		ipModel.setServerIpAddress(IPUtil.localIp());
		return ResultModel.ok(ipModel);
	}
}

五、过程中用到的工具类和实体

过程中用到了ResultModel实体和ResultCode枚举类,如果作为测试来用,其实没必要,这里是为后续章节做铺垫,将实体统一化,所以才多出了ResultModel实体和ResultCode枚举类。

IPUtil:

package cn.pomit.springbootwork.zkserver.util;

import java.net.InetAddress;
import java.net.UnknownHostException;

import javax.servlet.http.HttpServletRequest;

public class IPUtil {
	/**
	 * @Description: 获取客户端IP地址
	 */
	public static String getIpAddr(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
			if (ip.equals("127.0.0.1")) {
				// 根据网卡取本机配置的IP
				InetAddress inet = null;
				try {
					inet = InetAddress.getLocalHost();
				} catch (Exception e) {
					e.printStackTrace();
				}
				ip = inet.getHostAddress();
			}
		}
		// 多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
		if (ip != null && ip.length() > 15) {
			if (ip.indexOf(",") > 0) {
				ip = ip.substring(0, ip.indexOf(","));
			}
		}
		return ip;
	}

	/**
	 * 获取的是本地的IP地址
	 * 
	 * @return
	 */
	public static String localIp() {
		String result = "";
		try {
			InetAddress address = InetAddress.getLocalHost();
			result = address.getHostAddress();
		} catch (UnknownHostException e) {
			e.printStackTrace();
		}
		return result;
	}
}

IpModel :

package cn.pomit.springbootwork.zkserver.model;

public class IpModel {
	private String clientIpAddress;
	private String serverIpAddress;

	public String getClientIpAddress() {
		return clientIpAddress;
	}

	public void setClientIpAddress(String clientIpAddress) {
		this.clientIpAddress = clientIpAddress;
	}

	public String getServerIpAddress() {
		return serverIpAddress;
	}

	public void setServerIpAddress(String serverIpAddress) {
		this.serverIpAddress = serverIpAddress;
	}

}

ResultModel:

package cn.pomit.springbootwork.zkserver.model;

/**
 * @author cff
 */
public class ResultModel {

	private String errorCode;
	private String message;
	private Object data;

	public ResultModel() {

	}

	public ResultModel(String errorCode, String message) {
		this.errorCode = errorCode;
		this.message = message;
	}

	public ResultModel(String errorCode, String message, Object data) {
		this.errorCode = errorCode;
		this.message = message;
		this.data = data;
	}

	public ResultModel(ResultCode resultCodeEnum, Object data) {
		this.errorCode = resultCodeEnum.getCode();
		this.message = resultCodeEnum.getDesc();
		this.data = data;
	}

	public ResultModel(ResultCode resultCodeEnum) {
		this.errorCode = resultCodeEnum.getCode();
		this.message = resultCodeEnum.getDesc();
	}

	public String geterrorCode() {
		return errorCode;
	}

	public void seterrorCode(String errorCode) {
		this.errorCode = errorCode;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public Object getData() {
		return data;
	}

	public void setData(Object data) {
		this.data = data;
	}

	public static ResultModel ok() {
		return new ResultModel(ResultCode.CODE_00000);
	}

	public static ResultModel ok(Object data) {
		return new ResultModel(ResultCode.CODE_00000, data);
	}

	public static ResultModel error() {
		return new ResultModel(ResultCode.CODE_00001);
	}

	public static ResultModel error(String msg) {
		return new ResultModel(ResultCode.CODE_00001.getCode(), msg);
	}

	public static ResultModel error(String msg, Object data) {
		return new ResultModel(ResultCode.CODE_00001.getCode(), msg, data);
	}

	public static ResultModel unAuth() {
		return new ResultModel(ResultCode.CODE_40004);
	}
}

ResultCode:

package cn.pomit.springbootwork.zkserver.model;

/**
 * 响应码及其描述 Created by txl on 15/7/9.
 */
public enum ResultCode {

	/**
	 * 通用
	 */
	CODE_00000("00000", "操作成功"), CODE_00001("00001", "请求失败"), CODE_00002("00002", "错误的请求方法"), CODE_00003("00003", "非法的参数字段"), CODE_00004("00004", "异常抛出"), CODE_00005("00005", "权限不足"), CODE_00006("00006", "分页limit参数错误"), CODE_00007("00007", "分页offset参数错误"), CODE_00009("00009", "请求过于频繁"), CODE_00010("00010", "数据已存在"), CODE_00011("00011", "数据不存在"), CODE_00012("00012", "参数缺失"), CODE_00013("00013", "系统维护中"), CODE_00014("00014", "token缺失"), CODE_00015("00015", "token失效"), CODE_00016("00016", "签名错误"),

	CODE_10000("10000", "操作部分成功"),
	/**
	 * 系统
	 */
	CODE_30000("30000", "系统ID错误"),

	/**
	 * 授权
	 */
	CODE_40001("40001", "用户未找到"), CODE_40002("40002", "该用户状态异常"), CODE_40003("40003", "该用户已被删除"), CODE_40004("40004", "授权异常"),

	CODE_99999("99999", "签名无效");

	private String code;
	private String desc;

	ResultCode(String code, String desc) {
		this.code = code;
		this.desc = desc;
	}

	public String getCode() {
		return code;
	}

	public String getDesc() {
		return desc;
	}

	/**
	 * 根据code匹配枚举
	 * 
	 * @param code
	 * @return
	 */
	public static ResultCode getResultCodeByCode(String code) {
		for (ResultCode resultCode : ResultCode.values()) {
			if (code.equals(resultCode.getCode())) {
				return resultCode;
			}
		}
		return null;
	}

	public static ResultCode getResultCodeByDesc(String desc) {
		for (ResultCode resultCode : ResultCode.values()) {
			if (desc.equals(resultCode.getDesc())) {
				return resultCode;
			}
		}
		return null;
	}
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-08-13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • SpringCloud技术指南系列(六)服务注册发现之Zookeeper服务注册
    • 一、Zookeeper注册中心
      • 二、引入依赖
        • 三、配置zookeeper服务注册
          • 四、启动服务注册
            • 3.1 启动类
            • 3.2 开放服务
          • 五、过程中用到的工具类和实体
          相关产品与服务
          微服务引擎 TSE
          微服务引擎(Tencent Cloud Service Engine)提供开箱即用的云上全场景微服务解决方案。支持开源增强的云原生注册配置中心(Zookeeper、Nacos 和 Apollo),北极星网格(腾讯自研并开源的 PolarisMesh)、云原生 API 网关(Kong)以及微服务应用托管的弹性微服务平台。微服务引擎完全兼容开源版本的使用方式,在功能、可用性和可运维性等多个方面进行增强。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档