背景

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

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

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

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

公司的产品的服务都是发布到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:2183
timeout: 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;
}
// 平台启动后加载
@PostConstruct
public 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);
} @Override
public 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已经连接上了。

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

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

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

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

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

通过工具查看到我们的服务目录节点路径:/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 { @Autowired
private 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微服务平台的更多相关文章

  1. 【译文】用Spring Cloud和Docker搭建微服务平台

    by Kenny Bastani Sunday, July 12, 2015 转自:http://www.kennybastani.com/2015/07/spring-cloud-docker-mi ...

  2. java springboot activemq 邮件短信微服务,解决国际化服务的国内外兼容性问题,含各服务商调研情况

    java springboot activemq 邮件短信微服务,解决国际化服务的国内外兼容性问题,含各服务商调研情况 邮件短信微服务 spring boot 微服务 接收json格式参数 验证参数合 ...

  3. Spring Cloud和Docker搭建微服务平台

    用Spring Cloud和Docker搭建微服务平台 This blog series will introduce you to some of the foundational concepts ...

  4. java springboot整合zookeeper入门教程(增删改查)

    java springboot整合zookeeper增删改查入门教程 zookeeper的安装与集群搭建参考:https://www.cnblogs.com/zwcry/p/10272506.html ...

  5. 智能家居巨头 Aqara 基于 KubeSphere 打造物联网微服务平台

    背景 从传统运维到容器化的 Docker Swarm 编排,从 Docker Swarm 转向 Kubernetes,然后在 Kubernetes 运行 SpringCloud 微服务全家桶,到最终拥 ...

  6. 微服务平台(Micro Service Platform : MSP)旨在提供一个集开发、测试、运维于一体的开发者专属平台,让开发者能快速构建或使用微服务,让开发更简单,让运维更高效。

    微服务平台(Micro Service Platform : MSP)旨在提供一个集开发.测试.运维于一体的开发者专属平台,让开发者能快速构建或使用微服务,让开发更简单,让运维更高效. MSP采用业界 ...

  7. SpringBoot + Dubbo + zookeeper 搭建简单分布式服务

    SpringBoot + Dubbo + zookeeper 搭建简单分布式服务 详细操作及源码见: https://github.com/BillyYangOne/dubbo-springboot

  8. 一站式入口服务|爱奇艺微服务平台 API 网关实战 原创 弹性计算团队 爱奇艺技术产品团队

    一站式入口服务|爱奇艺微服务平台 API 网关实战 原创 弹性计算团队 爱奇艺技术产品团队

  9. surging 将推出社区版微服务平台

    前言 对于.NET大家并不陌生,有大批的企业选择.NET作为公司构建多种应用的开发平台,但是近几年随着微服务,大数据,移动端,物联网兴起,而后.NET社区生态没有跟上时代的步伐,已开始趋于没落,而其中 ...

随机推荐

  1. 利用 Ansiable 自动化部署 Veeam Backup & Replication 9.5U4b

    利用 Ansiable 自动化部署 Veeam Backup & Replication 9.5U4b 前言 上周出差期间接到一个做CMP(云管平台)Partner的需求,要在无人值守的安装 ...

  2. Xbim.GLTF源码解析(四):轻量化处理

    原创作者:flowell,转载请标明出处:https://www.cnblogs.com/flowell/p/10839433.html 在IFC标准中,由IfcRepresentationMap支持 ...

  3. 前端技术之:Prisma Demo服务部署过程记录

    安装前提条件: 1.已经安装了docker运行环境 2.以下命令执行记录发生在MackBook环境 3.已经安装了PostgreSQL(我使用的是11版本) 4.Node开发运行环境可以正常工作   ...

  4. Linux基于webRTC的二次开发(一)

    最近在做Linux平台下webRTC的二次开发,一路摸索,中间踩了不少坑,这一篇博客先来简单介绍下Linux上如何使用GCC编译webRTC. 为什么使用GCC编译? 这其实是无奈之举,Linux下w ...

  5. Logback MDC

    Mapped Diagnostic Contexts (MDC)   (译:诊断上下文映射) Logback的设计目标之一是审计和调试复杂的分布式应用程序.大多数实际的分布式系统需要同时处理来自多个客 ...

  6. 腾讯新闻构建高性能的 react 同构直出方案

    在腾讯新闻抢金达人活动 node 同构直出渲染方案的总结文章中我们整体了解了下同构直出渲染方案在我们项目中的使用.正如我在上篇文章结尾所说的: 应用型技术的难点不是在克服技术问题,而是在于能够不断的结 ...

  7. Vue.js应用基础

    声明 这篇博文是我的Vue学习记录,其中参杂了不少我个人的理解,由于我并没有继续学习Vue的源码,所以不能保证这些理解都是正确的.如果这篇博文有幸被你读到,请带着批判的心情去审视它. 如果你发现了其中 ...

  8. 『题解』洛谷P4016 负载平衡问题

    title: categories: tags: - mathjax: true --- Problem Portal Portal1:Luogu Portal2: LibreOJ Descripti ...

  9. 最新开源JavaScript 图表库 ECharts推荐

    ECharts是一款由百度前端技术部开发的,基于Javascript的数据可视化图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表. ECharts 提供大量常用的数据可视化图表,底层基于Z ...

  10. css3自定义移动端滚动条

    css3自定义移动端滚动条<pre>/*定义滚动条宽 高度是根据内容设置的高度决定的*/::-webkit-scrollbar{ width: 5px;} /*定义滚动条轨道 内阴影+圆角 ...