SpringBoot 整合 Zookeeper 接入Starring微服务平台

本文主要是介绍SpringBoot 整合 Zookeeper 接入Starring微服务平台,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

背景

烟雨红尘 https://wap.zuxs.net/

最近接的一个项目是基于公司产品Starring做的微服务支付平台,纯后台项目,实现三方支付公司和银行接口来完成用户账户扣款,整合成通用支付接口发布给前端调用。

但是扯蛋了,这边前端什么都不想做,只想我们提供一个链接,用户可以选择支付方式进行支付,这样的话相当于咱们又得起一个WEB版的收银台Project。

最近SpringBoot挺流行的,那就单独给起一个H5项目跑几个页面,调用后台的支付接口就完事了,如下?

image

最终的系统架构成了这样吧,随便画一画,请客官别吐槽。

公司的产品的服务都是发布到Zookeeper注册中心的,结果我们SpringBoot收银台成了直连某个IP端口,要是交易量一起来把直连的12001压垮了怎么办?

这样显然会存在问题,就因为一个收银台项目把整个微服务支付平台变成了单节点,所以我们收银台SpringBoot项目也必须连到上面的ZK中去查找平台服务。

环境

SpringBoot 2.2.1.Release

解决思路

从单web项目转成基于zookeeper调用的微服务项目:

1、Registry:服务注册,公司产品Starring 采取Zookeeper 作为我们的注册中心,我们现在要做的就是订阅服务。

2、Provider:服务提供者(生产者),提供具体的服务实现,这个是支付后台提供的服务。

3、Consumer:消费者,从注册中心中订阅服务,这个就是我们这边收银台要实现的功能啦。

4、Monitor:监控中心,RPC调用次数和调用时间监控,这块公司存在

从上图中我们可以看出RPC 服务调用的过程主要为:

1、生产者发布服务到服务注册中心

2、消费者在服务注册中心中订阅服务

3、消费者调用已注册的服务

操作步骤

A、配置文件

B、创建自己的Zookeeper连接

C、查找自己需要的服务

D、服务调用

A、配置文件

1、Maven 配置文件 pom.xml,引入zookeeper和zkclient两个包。

        <dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.5.6</version><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></exclusion><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId></exclusion></exclusions></dependency><dependency><groupId>com.101tec</groupId><artifactId>zkclient</artifactId><version>0.11</version></dependency>

排除slf4j是因为和其他jar包冲突,启动时检查报错。

 

2、SpringBoot配置文件 application.yml 增加zookeeper配置

zookeeper:address: serverhost:2181,serverhost:2182,serverhost:2183timeout: 20000

 

B、创建Zookeeper连接

SpringBoot项目启动后,自动连接Zookeeper配置中心,并获取到zookeeper实例,只需要连接一次,所以使用的单例。

关注SpringBoot平台启动后执行事件【@PostConstruct 】

这里需要注意,尝试过多种平台后执行事件来执行connect方法,只有这种方式在平台加载完所有Bean后执行。其他的方式下,无法获取Zookeeper中的配置。放在主函数后面执行,也不行。

package com.adtec.pay.util;import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;@Component
public class ZKWatcher implements Watcher {@Value("${zookeeper.address}")public String ZK_ADDRESS;@Value("${zookeeper.timeout}")public int ZK_TIMEOUT;private static ZKWatcher instance = null;private CountDownLatch latch = new CountDownLatch(1);private ZooKeeper zooKeeper;public ZKWatcher() {}public static ZKWatcher getInstance() {if (instance == null) {instance = new ZKWatcher();}return instance;}// 平台启动后加载@PostConstructpublic void connect() throws IOException {zooKeeper = new ZooKeeper(ZK_ADDRESS, ZK_TIMEOUT, this);try {latch.await();} catch (InterruptedException e) {e.printStackTrace();}setZooKeeper(zooKeeper);System.out.println("Zookeeper已连接成功:" + ZK_ADDRESS);}@Overridepublic void process(WatchedEvent event) {if (event.getState() == Event.KeeperState.SyncConnected) {latch.countDown();}}public ZooKeeper getZooKeeper() {return zooKeeper;}public void setZooKeeper(ZooKeeper zooKeeper) {this.zooKeeper = zooKeeper;}
}
C、查找自己的服务

好了,启动项目,到这里zookeeper已经连接上了。

image

现在咱们要发请求到后台,该怎么在注册中心找到自己需要的服务呢 ?

上面也已经提到整个微服务运行模式,由生产者(Starring支付平台)发布服务到 注册中心(Zookeeper),我们收银台项目是消费者要去订阅服务的。也就是我们得去注册中心搜服务。

所以我们首先得知道生产者发布的服务到注册中心是一个什么路径,就是生产者发布到 Zookeeper的目录节点。

稍微要懂一点Zookeeper知识,你才知道怎么查节点。不懂的话,百度一下,或者看一下别人的: https://blog.csdn.net/java_66666/article/details/81015302,如果还看不会,那劝你洗洗睡吧。

这里可以推荐一个图形界面查Zookeeper的工具,如下图:

image

通过工具查看到我们的服务目录节点路径:/Inst/cty/800002/V1.0/IcpPayReq/V1.0

我们要调用的服务是:【IcpPayReq】,也就是我们定义的服务码。

既然知道路径,知道服务码,事情就和把大象塞进冰箱需要几步一样。

1、获取Zookeeper连接实例。

2、根据目录节点获取服务实例。

3、随机选择其中一个实例,获取URL。

获取请求的类如下:

package com.adtec.pay.util;import org.apache.zookeeper.ZooKeeper;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;import java.util.LinkedList;
import java.util.List;
import java.util.Random;@Component
public class ZKListener {
//    private static String SERVER_PATH = "/Inst/cty/800002/V1.0/IcpPayReq/V1.0";private String SERVER_PATH = "";private ZooKeeper zooKeeper;private List<String> paths = new LinkedList<>();public void findTranUrl(String tranCode) {if (!StringUtils.isEmpty(tranCode)) {SERVER_PATH = "/Inst/cty/800002/V1.0/" + tranCode + "/V1.0";}getChilds();}private void getChilds() {List<String> ips = new LinkedList<>();zooKeeper = ZKWatcher.getInstance().getZooKeeper();try {//获取子节点List<String> childs = zooKeeper.getChildren(SERVER_PATH, false);for (String child : childs) {byte[] data = zooKeeper.getData(SERVER_PATH + "/" + child, false, null);String path = new String(data, "UTF-8");ips.add(path);}this.paths = ips;} catch (Exception e) {e.printStackTrace();}}public String getPath() {if (paths.isEmpty()) {return null;}//这里我们随机获取一个ip端口使用int index = new Random().nextInt(paths.size());return paths.get(index);}
}

这样就能找到真实请求地址了,愉快的发送请求吧。

D、服务调用

这里我写了一个通用类,因为调用的服务不会只有一个,服务目录路径相同服务码不同就可以通用了。

package com.adtec.pay.entity;import com.adtec.pay.util.CommUtil;
import com.adtec.pay.util.ZKListener;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;public class Request {@Autowiredprivate ZKListener zkListener;@Value("${spring.profiles.active}")private String env;protected String url;protected Class<? extends Response> responseClass;public Request(String tranCode, Class<? extends Response> responseClass) {if (env.equals("dev")){if (tranCode.equals("HosOrderQuery")) {this.url = "http://serverhost:13008/HttpServer/MEDICAL_MNG_SVR/QryOrderDetail";} else if (tranCode.equals("IcpPayReq")) {this.url = "http://serverhost:13008/HttpServer/MEDICAL_MNG_SVR/IcpPayReq";} else if (tranCode.equals("QryOrderDetail")) {this.url = "http://serverhost:13008/HttpServer/MEDICAL_MNG_SVR/QryOrderDetail";}} else {zkListener.findTranUrl(tranCode);String path = zkListener.getPath();ZKStatusEntity zkStatus = JSONObject.parseObject(path, ZKStatusEntity.class);this.url = zkStatus.getCOM_HTTP().getURL() + "/" + tranCode;}this.responseClass = responseClass;}public void setUrl(String url) {this.url = url;}public void setResponseClass(Class<? extends Response> responseClass) {this.responseClass = responseClass;}public <T> Response send(Request request) {return CommUtil.httpRequestJSON(url, request, responseClass);}}

 

总结

这次通过做这个项目,摸索了很多SpringBoot的细节,遇到了很多看着很小又很影响进度的问题。

1、项目启动后加载所有Bean文件后启动,尝试了很多种方式。

2、通用的请求类整合,泛型确实用的不太熟悉,需要再多理解。

3、新的HttpClient包包名 org.apache.httpcomponents 的请求方法调试,网上很多都是老的方法。

 

搞定,收工。 

刚发出来,那什么源码寺就copy过去了,也不标识,所以附上原文地址:https://www.cnblogs.com/laramia/p/11978271.html

这篇关于SpringBoot 整合 Zookeeper 接入Starring微服务平台的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/161067

相关文章

Spring Boot 实现 IP 限流的原理、实践与利弊解析

《SpringBoot实现IP限流的原理、实践与利弊解析》在SpringBoot中实现IP限流是一种简单而有效的方式来保障系统的稳定性和可用性,本文给大家介绍SpringBoot实现IP限... 目录一、引言二、IP 限流原理2.1 令牌桶算法2.2 漏桶算法三、使用场景3.1 防止恶意攻击3.2 控制资源

Mac系统下卸载JAVA和JDK的步骤

《Mac系统下卸载JAVA和JDK的步骤》JDK是Java语言的软件开发工具包,它提供了开发和运行Java应用程序所需的工具、库和资源,:本文主要介绍Mac系统下卸载JAVA和JDK的相关资料,需... 目录1. 卸载系统自带的 Java 版本检查当前 Java 版本通过命令卸载系统 Java2. 卸载自定

springboot下载接口限速功能实现

《springboot下载接口限速功能实现》通过Redis统计并发数动态调整每个用户带宽,核心逻辑为每秒读取并发送限定数据量,防止单用户占用过多资源,确保整体下载均衡且高效,本文给大家介绍spring... 目录 一、整体目标 二、涉及的主要类/方法✅ 三、核心流程图解(简化) 四、关键代码详解1️⃣ 设置

Java Spring ApplicationEvent 代码示例解析

《JavaSpringApplicationEvent代码示例解析》本文解析了Spring事件机制,涵盖核心概念(发布-订阅/观察者模式)、代码实现(事件定义、发布、监听)及高级应用(异步处理、... 目录一、Spring 事件机制核心概念1. 事件驱动架构模型2. 核心组件二、代码示例解析1. 事件定义

SpringMVC高效获取JavaBean对象指南

《SpringMVC高效获取JavaBean对象指南》SpringMVC通过数据绑定自动将请求参数映射到JavaBean,支持表单、URL及JSON数据,需用@ModelAttribute、@Requ... 目录Spring MVC 获取 JavaBean 对象指南核心机制:数据绑定实现步骤1. 定义 Ja

javax.net.ssl.SSLHandshakeException:异常原因及解决方案

《javax.net.ssl.SSLHandshakeException:异常原因及解决方案》javax.net.ssl.SSLHandshakeException是一个SSL握手异常,通常在建立SS... 目录报错原因在程序中绕过服务器的安全验证注意点最后多说一句报错原因一般出现这种问题是因为目标服务器

Java实现删除文件中的指定内容

《Java实现删除文件中的指定内容》在日常开发中,经常需要对文本文件进行批量处理,其中,删除文件中指定内容是最常见的需求之一,下面我们就来看看如何使用java实现删除文件中的指定内容吧... 目录1. 项目背景详细介绍2. 项目需求详细介绍2.1 功能需求2.2 非功能需求3. 相关技术详细介绍3.1 Ja

springboot项目中整合高德地图的实践

《springboot项目中整合高德地图的实践》:本文主要介绍springboot项目中整合高德地图的实践,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一:高德开放平台的使用二:创建数据库(我是用的是mysql)三:Springboot所需的依赖(根据你的需求再

spring中的ImportSelector接口示例详解

《spring中的ImportSelector接口示例详解》Spring的ImportSelector接口用于动态选择配置类,实现条件化和模块化配置,关键方法selectImports根据注解信息返回... 目录一、核心作用二、关键方法三、扩展功能四、使用示例五、工作原理六、应用场景七、自定义实现Impor

SpringBoot3应用中集成和使用Spring Retry的实践记录

《SpringBoot3应用中集成和使用SpringRetry的实践记录》SpringRetry为SpringBoot3提供重试机制,支持注解和编程式两种方式,可配置重试策略与监听器,适用于临时性故... 目录1. 简介2. 环境准备3. 使用方式3.1 注解方式 基础使用自定义重试策略失败恢复机制注意事项