服务调用

通过服务调用(Service-to-service Invocation),服务可以使用 gRPC 或 HTTP 这样的标准协议来发现并可靠地与其他服务通信。

Dapr采用边车(Sidecar)、去中心化的架构。 要使用Dapr来调用服务,可以在任意Dapr实例上使用invoke这个API。 边车编程模型鼓励每个服务与自己的Dapr实例对话。 Dapr实例会相互发现并进行通信。

文章持续更新,微信搜索「万猫学社」第一时间阅读,关注后回复「电子书」,免费获取12本Java必读技术书籍。

创建项目

创建两个SpringBoot项目,分别命名为:invoke-serverinvoke-clientinvoke-server作为下游服务,被invoke-client调用,具体调用过程如下图:

调用过程包括:

  1. invoke-client服务对invoke-server服务发起HTTP或gRPC调用的时候,访问invoke-client服务的Dapr实例。
  2. invoke-client服务的Dapr实例通过运行在给定托管平台上服务名解析组件(Name Resolution Component)发现了运行在此Dapr环境中的invoke-server服务。
  3. invoke-client服务的Dapr实例将消息转发到服务invoke-server服务的Dapr实例。Dapr实例之间的所有调用考虑到性能都优先使用gRPC。 仅服务与Dapr实例之间的调用可以是HTTP或gRPC。
  4. invoke-server服务的Dapr实例将请求转发至invoke-server服务上的特定端点或方法,随后运行其业务逻辑代码。
  5. invoke-server服务返回响应信息给invoke-client服务时,响应信息给将转至invoke-server服务的Dapr实例。
  6. invoke-server服务的Dapr实例消息转发至invoke-client服务的Dapr实例。
  7. invoke-client服务接收到其Dapr实例的响应信息。

文章持续更新,微信搜索「万猫学社」第一时间阅读,关注后回复「电子书」,免费获取12本Java必读技术书籍。

编写invoke-server的代码

调用/send接口时,返回对应信息,主要代码如下:

package one.more.society.invoke.server;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; @Slf4j
@RestController
public class InvokeServerController { @RequestMapping(value = "/send", method = RequestMethod.POST)
public InvokeResponse send(@RequestBody InvokeRequest request) {
log.info("send - request:{}", request); InvokeResponse response = new InvokeResponse();
response.setCode(1);
response.setStatus("ok");
response.setMsgId(System.nanoTime());
response.setMsgContent("I konw you said: " + request.getMsgContent()); return response;
}
}

其中,InvokeRequestInvokeResponse的源码如下:

package one.more.society.invoke.server;

import lombok.Data;

@Data
public class InvokeRequest { private Long msgId;
private String msgContent;
}
package one.more.society.invoke.server;

import lombok.Data;

@Data
public class InvokeResponse { private int code;
private String status;
private Long msgId;
private String msgContent;
}

application.properties中配置:

server.port=30001

文章持续更新,微信搜索「万猫学社」第一时间阅读,关注后回复「电子书」,免费获取12本Java必读技术书籍。

编写invoke-client

invoke-client项目的pom.xml文件中添加如下依赖:

<dependency>
<groupId>io.dapr</groupId>
<artifactId>dapr-sdk-springboot</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.3</version>
</dependency>

注入一个DaprClient的bean:

@Configuration
public class DaprConfig { private static final DaprClientBuilder BUILDER = new DaprClientBuilder(); @Bean
public DaprClient buildDaprClient() {
return BUILDER.build();
}
}

调用invoke-server/send接口,主要代码如下:

package one.more.society.invoke.client;

import io.dapr.client.DaprClient;
import io.dapr.client.domain.HttpExtension;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; @Slf4j
@RestController
public class InvokeClientController { @Autowired
private DaprClient client; private static final String SERVICE_APP_ID = "invoke-server";
private static final String METHOD_NAME = "send"; @RequestMapping(value = "/say", method = RequestMethod.GET)
public InvokeResponse say(String message) {
log.info("send - message:{}", message); InvokeRequest request = new InvokeRequest();
request.setMsgId(System.nanoTime());
request.setMsgContent(message); InvokeResponse response = client.invokeMethod(
SERVICE_APP_ID,
METHOD_NAME,
request,
HttpExtension.POST,
InvokeResponse.class).block(); return response;
}
}

其中,InvokeRequestInvokeResponse的源码与invoke-server中是一样的。

application.properties中配置:

server.port=30002

文章持续更新,微信搜索「万猫学社」第一时间阅读,关注后回复「电子书」,免费获取12本Java必读技术书籍。

启动服务

在启动之前先用mvn命令打包:

mvn clean package

invoke-server项目的目录中执行以下命令,启动invoke-server服务:

dapr run --app-id invoke-server --app-port 30001 --dapr-http-port 31001 -- java -jar target/invoke-server-0.0.1-SNAPSHOT.jar

invoke-client项目的目录中执行以下命令,启动invoke-client服务:

dapr run --app-id invoke-client --app-port 30002 --dapr-http-port 31002 -- java -jar target/invoke-client-0.0.1-SNAPSHOT.jar

在Dapr Dashboard中看到:

两个服务都已经启动成功。

访问http://localhost:30002/say?message=OneMoreSociety验证整个调用流程:

可以看到服务之间的调用没有问题,并返回了预想的结果。

文章持续更新,微信搜索「万猫学社」第一时间阅读,关注后回复「电子书」,免费获取12本Java必读技术书籍。

名称解析组件

为了启用服务发现和服务调用,Dapr使用可插拔的名称解析组件。 Kubernetes名称解析组件使用Kubernetes DNS服务来解析集群中运行的其他服务的位置;自托管机器可以使用mDNS名称解析组件。

Consul名称解析组件可以在任何托管环境中使用,包括Kubernetes或自托管环境。下面让我们来尝试一下,使用Consul作为名称解析组件。

在用户目录下的.dapr文件夹中,找到config.yaml文件。在该文件中,添加一个nameResolutionspec ,并将component字段设置为consul,比如:

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
name: daprConfig
spec:
nameResolution:
component: "consul"
configuration:
client:
address: "127.0.0.1:8500"
selfRegister: true

重新启动服务,可以在日志中看到注册到了Consul上:

time="14:28:54.4540593+08:00" level=info msg="service:invoke-client registered on consul agent" app_id=invoke-client instance=OneMoreSociety scope=dapr.contrib type=log ver=1.7.3
time="14:28:54.4550937+08:00" level=info msg="Initialized name resolution to consul" app_id=invoke-client instance=OneMoreSociety scope=dapr.runtime type=log ver=1.7.3

在Consul中也可以看到两个服务都已经注册上去了,如下图:

值得注意的是:Consul名称解析组件目前还处于Alpha状态,最好不要在生产环境使用。

更详细的配置说明见下表:

配置项 是否必填 数据类型 说明 示例
client N Config 配置客户端与 Consul 代理的连接。 如果留空,将使用默认值,即127.0.0.1:8500 192.168.0.111:8500
queryOptions N QueryOptions 配置用于解决健康服务的查询,默认为UseCache:true UseCache: false,
Datacenter: "myDC"
checks N AgentServiceCheck数组 当进行注册服务时,配置健康检查。默认到Dapr实例检测健康端点。
tags N string数组 在注册服务服务时包含的额外标签 - "dapr"
meta N string字典 在注册服务服务时包含的额外的元数据 DAPR_METRICS_PORT: "${DAPR_METRICS_PORT}"
daprPortMetaKey N string 用于在服务解析过程中从Consul服务元数据中获取Dapr实例端口的 key,它也将用于在注册时在元数据中设置Dapr实例端口。 默认为 DAPR_PORT "DAPR_TO_DAPR_PORT"
selfRegister N boolean 控制Dapr实例是否会向Consul注册服务,默认为 false true
advancedRegistration N AgentServiceRegistration 通过配置完全控制服务注册结果。 如果配置此项,Checks、 Tags、 Meta 和 SelfRegister的任何配置将被忽略。

配置示例:

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
name: appconfig
spec:
nameResolution:
component: "consul"
configuration:
client:
address: "127.0.0.1:8500"
selfRegister: true
checks:
- name: "Dapr Health Status"
checkID: "daprHealth:${APP_ID}"
interval: "15s",
http: "http://${HOST_ADDRESS}:${DAPR_HTTP_PORT}/v1.0/healthz"
- name: "Service Health Status"
checkID: "serviceHealth:${APP_ID}"
interval: "15s",
http: "http://${HOST_ADDRESS}:${APP_PORT}/health"
tags:
- "dapr"
- "v1"
- "${OTHER_ENV_VARIABLE}"
meta:
DAPR_METRICS_PORT: "${DAPR_METRICS_PORT}"
DAPR_PROFILE_PORT: "${DAPR_PROFILE_PORT}"
daprPortMetaKey: "DAPR_PORT"
queryOptions:
useCache: true
filter: "Checks.ServiceTags contains dapr"

最后,感谢你这么帅,还给我点赞

微信公众号:万猫学社

微信扫描二维码

关注后回复「电子书」

获取12本Java必读技术书籍

Dapr在Java中的实践 之 服务调用的更多相关文章

  1. Java进阶(三十一) Web服务调用

    Java进阶(三十一) Web服务调用 前言 有朋友问了一个问题:如何调用已知的音乐服务接口,服务文档如下: https://www.evernote.com/shard/s744/sh/c37cd5 ...

  2. 中文乱码在java中URLEncoder.encode方法要调用两次解决

    中文乱码在java中URLEncoder.encode方法要调用两次解决 一.场景: 1.我在客户端要通过get方式调用服务器端的url,将中文参数做utf-8编码,需要在js中两次的进行编码,服务器 ...

  3. java中使用axis发布和调用webService及dom4j解析xml字符串

    工作中需要调用webService服务,这里记录一下如何在java中发布和调用webService. 需要的jar包: webService服务端: import javax.jws.WebMetho ...

  4. 关于Java中基类构造器的调用问题

    在<Java编程思想>第7章复用类中有这样一段话,值得深思.当子类继承了父类时,就涉及到了基类和导出类(子类)这两个类.从外部来看,导出类就像是一个与基类具有相同接口的新类,或许还会有一些 ...

  5. C++/Java中继承关系引发的调用关系详解

    C++: 这里引用到了 http://blog.csdn.net/haoel/article/details/1948051/ 中的内容,还请提前阅读陈大神的这篇博客后在阅读本篇. 覆盖,实现多态的基 ...

  6. java中静态方法和非静态方法调用的一点小困扰,已解决。

    public static void main(String[] args) { // TODO Auto-generated method stub SimpleGui1B gui=new Simp ...

  7. Java中多线程启动,为什么调用的是start方法,而不是run方法?

    前言 大年初二,大家新年快乐,我又开始码字了.写这篇文章,源于在家和基友交流的时候,基友问到了,我猛然发现还真是这么回事,多线程启动调用的都是start,那么为什么没人掉用run呢?于是打开我的ide ...

  8. 实例详解Java中如何对方法进行调用

    原文源自http://www.jb51.net/article/73827.htm 方法调用Java支持两种调用方法的方式,根据方法是否返回值来选择. 当程序调用一个方法时,程序的控制权交给了被调用的 ...

  9. java中避免集合死链调用

    目录 1. 前言 2. 场景 3. 环境 3.1 开发环境准备 3.2 数据准备 3.2.1 Mysql数据库表及数据 3.2.2 redis库数据 4. 解决方式 5.完整代码 5.1Model 5 ...

  10. Java中的一个类怎么调用另一个类中的方法

    如果另一个类中的那个方法是私有的话,就不能直接调用到,如果是其他类型的话看情况,如果是静态的(static)话,直接用类名可以调用到,如果是非静态的,就需要利用另一个类的实例(也就是用那个类生成的对象 ...

随机推荐

  1. 字符串常见API(charCodeAt\fromCharCode)

    1.myStr.charCodeAt(num) 返回指定位置的字符的Unicode(是字符编码的一种模式)编码. 2.String.fromCharCode() String的意思就是不能用自己定义的 ...

  2. xcodebuild命令行工具使用详解

    xcodebuild命令行工具使用 如何通过命令行编译ios项目? xcodebuild是一个命令行工具,允许你从命令行对Xcode项目和工作区执行编译.查询.分析.测试和归档操作.它对项目中包含的一 ...

  3. Luogu P2574 XOR的艺术 P3870 [TJOI2009]开关 P2846 [USACO08NOV]光开关Light Switching SP7259 LITE - Light Switching

    四倍经验题 简单线段树qwq(那你怎么还调了好几个小时) 修改:\(ans[cur]=(r-l+1-ans[cur]);\) 点表示的区间有多长就是有多少盏灯 亮着的关掉 暗的开启 就是上述语句了. ...

  4. odoo 开发入门教程系列-模块交互

    模块交互 在上一章中,我们使用继承来修改模块的行为.在我们的房地产场景中,我们希望更进一步,能够为客户生成发票.Odoo提供了一个开发票模块,因此直接从我们的房地产模块创建发票是很简单的,也就是说,一 ...

  5. .NET无侵入自动化探针原理和主流实现

    前言 最近,我在微信公众号和博客园分享了一篇关于.NET微服务系统迁移至.NET 6.0的故事的文章,引起了许多读者的关注.其中,许多人对基于 OpenTelemetry .NET 的观测指标和无侵入 ...

  6. 一个.Net版本的ChatGPT SDK

    ChatGPT大火,用它来写代码.写表白书.写文章.写对联.写报告.写周边...... 啥都会! 个人.小公司没有能力开发大模型,但基于开放平台,根据特定的场景开发应用,却是非常火热的. 为了避免重复 ...

  7. vue将页面(dom元素)转换成图片,并保存到本地

    1 npm install html2canvas --save <template> <div class="QRCode-box"> <img i ...

  8. Python LOG-日志

    LOG https://www.cnblogs.com/yyds/p/6901864.html logging logging模块提供模块级别的函数记录日志 包括四大组件 1. 日志相关概念 日志 日 ...

  9. Locust 任务类介绍

    前言: 任务:简单的理解就是,你想要你脚本的虚拟用户去做哪些事,比如请求某一个接口,或者执行某一个事件 用户:可以理解为,执这个任务的实例主体,或者在locust 中,也可以认为是一群蝗虫 一.Tas ...

  10. AspNetCoreRateLimit应用于MVC项目求助

    AspNetCoreRateLimit应用于MVC项目求助 前言 之前发过一篇文章: .NET Core WebApi接口ip限流实践 - 妙妙屋(zy) - 博客园 (cnblogs.com) 然后 ...