SpringCloud-服务网关-Gateway

1.服务网关在微服务中的应用

(1)对外提供服务的难题分析:
微服务架构下的应用系统体系很庞大,光是需要独立部署的基础组件就有注册中心、配置中心和服务总线、Turbine异常聚合和监控大盘、调用链追踪器和链路聚合,还有Kaka和MQ之类的中间件,再加上拆分后的零散微服务模块。—个小系统都能轻松弄出20个左右的部署包。
如果采用localhost加端口的方式直接访问,如果这些服务—并都要提供给外部用户访问那该怎么办呢?可以让前端程序员加班加点在各个页面给各种不同请求配置URL和端口号,人不是问题,项目完成就行。也可以我们配一个URL,通过F5或者Nginx可以做路由,话是没错,可是这样就要让运维团队手工维护路由规则表,当我们新增删除节点或者因为更换机房导致IP变化的时候就很麻烦。因此我们需要引入—套机制来降低路由表的维护成本。
还有一个问题就是安全性,我们在提供外部服务的时候往往会加入一些访问控制,比如说下单接口不允许未登录用户的访问,有的服务还会通过一些JWT签名等防止客户端篡改数据。如果让每个服务提供者都实现同样的访问验证逻辑未免有些太繁琐,这样纯属是增加研发人员的怒气值,况且如果有一天我们需要更换权限认证方案,比如更换为OAuth2.0,难不成还要每个服务提供者都做变更?
我们如何对外提供服务,既能管好路由规则,还能做好访问控制呢?在这个背景下,API网关应运而生,接待所有来访请求。
(2)网关层
微服务引入一层专事专办的中间层。
两件事:
1.访问控制,看你是否有权限访问,拒绝未授权的来访者
2.引导指路 问清楚你要办的事,指一条明路。找到对应处理这些事的人

网关层引入后,微服务的架构变成:
在这里插入图片描述
网关层作为唯一的对外服务,外部请求不直接访问服务层。由网关层承接所有HTTP
请求,在实际应用中。我们会将Gateway与Nginx一同使用。
(3)访问控制和路由规则
访问控制:
主要包含两个方面的任务,具体的实现并不是由网关层提供的,但是网关作为一个载体承载了两个任务:
拦截请求:有的接口需要登录用户才能访问,对于这类接口的访问,网关层可以检查访问请求中是否携带令牌等身份信息,比兔HTTP Header中的Authorization或者token属性。如果没有携带令牌,说明没登录,可以直接返回403 Forbidden
鉴权:对于携带令牌的服务,我们需要验证令牌的真假,否则用户可以
通过伪造的令牌进行通信,对令牌校验失败的请求,或者令牌已经过期
的请求执行拒绝服务!

路由规则
路由规则包含两个方面,分别是URL映射和服务寻址
URL映射:在大多数情况下,客户端访问的HTTP URL往往不是我们在Controller里配置的真实路径,比如客户端可以发起请求"/password/update"来修改密码,但后台并没有这个服务,这时候就需要网关层做一个路由规则,将来访URL映射成真正的服务路径,比如将刚才的密码修改请求的路径映射到"/user/settings/security/password"请求
服务寻址URL映射:好了之后,网关层就需要找到可以提供服务的服务器地址,对于服务集群的话,还需要实现负载均衡策略。(在Spring Cloud中,Gateway是借助Eureka的服务发现机制来实现服务寻址的,负载均衡则依靠Ribbon)

2.第二代网关组件Gateway介绍

Gateway业务场景:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.Gateway体系架构解析

(打开Gateway的自动装配工厂,gatewayAutoConfiguration看,第一个就是Netty)

Netty是什么?在网络传输领域Netty就是身份的象征,它是非阻塞、高性能、高可靠的异步输入输出框架,用一个字概括就是"快"。这里我们不对Netty做深入探讨,但是需要了解下Netty在Gateway中主要应用在以下几个地方:
发起服务调用:由NettyRoutingFilter过滤器实现,底层采用基于Netty的HttpClient发起外部服务的调用
Response传输:由NettyResponseFilter过滤器实现,网络请求结束后要将Response回传给调用者

  • Socket连接:具体由ReactortNettyWebSocketClient类承接,通过Netty的Httpclient发起连接请求
    在Gateway中发起Request和回传Response之类的步骤都是通过一系列过滤翮完成的,有关过滤器的内容将在稍后介绍。

(正常HTTP调用与netty的http调用的区别:
核心区别:javax.servlet.http.HttpServletRequest主要用于服务器端的HTTP请求处理,而Netty的HttpClient用于客户端发起HTTP请求)

在这里插入图片描述
Client发起请求到服务网关之后,由NettyRoutingFilter底层的HttpClient(Netty组件)向
服务发起调用,调用结束后,Response有NettyResponseFilter再回传给客户端。有了netty加持,网络请求效率大幅提升!Netty贯穿从Request发起到Response结束的过程,承担了所有网络调用相关的任务

(1)Gateway自动装配:
在这里插入图片描述
AutoConfig: 作为核心自动装配主类,GatewayAutoConfiguration负责初始化所有的Route路由规则、Predicate断言工厂和Filter(包括Global Filter和Route Filter),这三样是Gateway吃饭的家伙,用来完成路由功能。AutoConfig也会同时加载Netty配置
LoadBalancerGlient: 这部分在AutoConfig完成之后由GatewayLoadBalancerClientAutoConfiguration负责加载,用来加载Ribbon和一系列负载均衡配置
ClassPathWarning:同样也是在AutoConfig完成之后触发(具体加载类为GatewayClassPathWarningAutoConfiguration),由于Gateway底层依赖Spring WebFlux的实现,所以它会检查项目是否加载了正确配置
Redis:在Gateway中Redis主要负责限流的功能。
除了上面几个核心装配工厂以外,还有两个打酱油的路人,它们并不直接参与Gateway的核心功能,但是会提供—些重要的支持功能:
GatewayMetricsAutoConfiguration:负责做一些统计工作,比如对所谓的“short task"运行时长和调用次数做统计
GatewayDiscoveryClientAutoConfiguration:服务发现客户端自动装配类

爬坑指南
Gateway项目启动出错,但是查来查去,发现也没有什么配置问题。这时候就要看一下是不是引入了错误的依赖,Gateway比较坑的一个地方是它基于WebFlux实现,因此它需要的依赖是spring-boot-starter-webflux,假如我们不小心引入了spring-boot-starter-web将导致启动问题,
由于我们大部分的Spring Cloud项目都依赖spring-boot-starter-web,所以很容易就误将其依赖导入到了Gateway项目中,碰到这种问题只要打印出依赖树,排查下错误依赖的来源,然后将它在pom中排除出去就好了。
路由流程
这里就涉及到了Gateway最核心的路由功能,路由主要由断言和过滤器配合来实现,我们把这部分内容拆分为3个小节,分别介绍路由的整体功能、断言的使用、过滤器原理和生命周期。

4.路由功能详解

Gateway网关的路由功能可不简简单单的转发请求,在请求到达网关再流转到指定服务之间发生了很多事!它不光可以拒绝请求,甚至可以篡改请求的参数!

一个route包含完整转发规则的路由,主要由一下三部分组成:

在这里插入图片描述
断言集合:断言是路由处理的第一个环节,它是路由的匹配规则,它决定了一个网络请求是否可以匹配给当前路由来处理。之所以它是一个集合的原因是我们可以给一个路由添加多个断言,当每个断言都匹配成功以后才算过了路由的第一关。有关断言的详细内容将在下一小节进行介绍
过滤器集合:如果请求通过了前面的断言匹配,那就表示它被当前路由正式接手了,接下来这个请求就要经过一系列的过滤器集合。过滤器的功能就是八仙过海各显神通了,可以对当前请求做一系列的操作,比如说权限验证,或者将其他非业务性校验的规则提到网关过滤器这一层。在过滤器这一层依然可以通过修改Response里的status Code达到中断效果,比如对鉴权失败的访问请求设置Status Code为403之后中断操作。有关过滤器的详细内容将在后面的小节介绍
URI:如果请求顺利通过过滤器的处理,接下来就到了最后一步,那就是转发请求。URI是统一资源标识符,它可以是一个具体的网址,也可以是IP+端口的组合,或者是Eureka中注册的服务名称

关于负载均衡:
对最后一步寻址来说,如果采用基于Eureka的服务发现机制,那么在Gateway的转发过程中可以采用服务注册名的方式来调用,后台会借助Ribbon实现负载均衡(可以为某个服务指定具体的负载均衡策略),其配置方式如:1b://FEIGN-SERVICE-PROVIDER/。前面的lb就是指代Ribbon作为LoadBalancer,

路由的规则流程:
在这里插入图片描述
Predicate Handler:具体承接类是RoutePredicateHandlerMapping。首先它获取所有的路由(配置的routes全集),然后依次循环每个Route,把应用请求与Route中配置的所有断言进行匹配,如果当前Route所有断言都验证通过,Predict Handler就选定当前的路由。这个模式是典型的职责链。
Filter Handler:在前一步选中路由后,由FilteringWebHandler将请求交给过滤器,在具体处理过程中,不仅当前Route中定义的过滤器会生效,我们在项目中添加的全局过滤器(Global Filter)也会一同参与。同学们看到图中有Pre Filter和Post Filter,这是指过滤器的作用阶段,我们在稍后的章节中再深入了解
寻址:这一步将把请求转发到URI指定的地址,在发送请求之前,所有Pre类型过滤器都将被执行,而Post过滤器会在调用请求返回之后起作用。

5.断言功能详解(Predict)

Predicate机制:
Predicate是Java 8中引入的一个新功能,就和我们平时在项目中写单元测试时用到的Assertion差不多,Predicate接收一个判断条件,返回一个ture或false的布尔值结果,告知调用方判断结果。你也可以通过and (与),or(或)和negative (非)三个操作符将多个Predicate串联在一块共同判断。

如果Gateway是挡在微服务前面的中介,那这个Predicate就是和中介的接头暗号。比如中介可以要求你的Request中必须带有某个指定的参数叫name,对应的值必须是一个指定的信息,如果你的Request中没有包含指定信息,或者指定信息错误,那就是断言失败。只有当你的请求完全和接头暗号匹配的时候,中介才能给你放行。

说白了predicate就是一种路由规则,通过gateway中丰富内置断言的组合,
我们就能让一个请求找到对应的route来处理。

断言的作用阶段:
在一个请求抵达网关层后,首先就要进行断言匹配,在满足所有断言之后
才会进入Filter阶段!

常用断言介绍:gateway提供了十多种内置断言:
路径匹配:path断言是最常用一个断言。
.route(r -> r.path(“/gateway/**”)
.uri(“lb://FEIGN-SERVICE-PROVIDER/”)
)
.route(r -> r.path(“/baidu”)
.uri(“http://baidu.com:80/”)
)
Path断言的使用非常简单,就像我们在Controller中配置@RequestPath的方式一样,在Path断言中填上—段URL匹配规则,当实际请求的URL和断言中的规则相匹配的时候,就下发到该路由中URI指定的地址,这个地址可以是一个具体的HTTP地址,也可以是Eureka中注册的服务名称。在上面的例子中,如果我们访问"Igateway/test”,这个路径将匹配到第一个路由。

Method断言:
这个断言是专门验证HTTP Method的,在下面的例子中,我们把Method断言和Path断言通过一个and连接符合并起来,共同作用于路由判断,当我们访问"lgateway/sample"并且HTTP Method是GET的时候,将适配下面的路由
.route(r -> r.path(“/gateway/“)
.and().method(HttpMethod.GET)
.uri(“lb://FEIGN-SERVICE-PROVIDER/”)
)
RequestParam匹配:请求断言也是业务中经常使用的,它会从ServerHttpRequest中
的Parameters列表中查询指定的属性,如下有两种不同的使用方式:

.route(r -> r.path(”/gateway/
”)
.and().method(HttpMethod.GET)
.and().query(“name”, “test”)
.and().query(“age”)
.uri(“lb://FEIGN-SERVICE-PROVIDER/”)
)
属性名验证:如query(“age”),此时断言只会验证QueryPrameters列表中是否包含了一个叫age的属性,并不会验证它的值
属性值验证:如query ( "“name” ,“test”),它不仅会验证name属性是否存在,还会验证它的值是不是和断言相匹配,比如当前的断言会验证请求参数中的name属性值是不是test,第二个参数实际上是一个用作模式匹配的正则表达式

**Header断言:这个断言会检查Header中是否包含了响应的属性,通常可以用来
验证请求是否携带了令牌:
.route(r -> r.path("/gateway/
")
.and().header(“Authorization”)
.uri(“lb://FEIGN-SERVICE-PROVIDER/”)
)
上面的断言指定Header中必须包含一个Authorization属性,Header断言和Query断言
一样,也可以通过传入两个参数形式对属性值进行检查

Cookie断言:
顾名思义,Cookie验证的是Cookie中保存的信息,Cookie断言和上面介绍的两种断言使用方式大同小异,唯一的不同是它必须连同属性值一同验证,不能单独只验证属性是否存在,示例如下:

.route(r -> r.path(“/gateway/**”)
.and().cookie(“name”, “test”)
.uri(“lb://FEIGN-SERVICE-PROVIDER/”)
)

时间片匹配:
时间匹配有三种模式,分别是Before、After和Between,这些断言指定了在什么时间范围内路由才会生效
.route(r -> r.path(“/gateway/**”)
.and().before(ZonedDateTime.now().plusMinutes(1))
.uri(“lb://FEIGN-SERVICE-PROVIDER/”)
)

自定义断言:
Gateway也提供了一个扩展方法,用来将自定义的断言应用到路由上。老师给出两点提示,希望同学们顺着这个方向来参考Gateway的源码,实现一个自定义断言,完成一个小功能:将所有请求参数大于5个的访问请求拦截掉,即RequestParam个数小于5个的请求才能被放行。
提示1:所有断言类都可以继承自AbstractRoutePredicateFactory
提示2:在路由配置时可以通过predicate或者asyncPredicate传入一个自定义断言

6.过滤器原理和生命周期

过滤器的工作模式:
Gateway的过滤器是一样的模型,他们经过优先级排序,所有网关调用请求从最高优先级的过滤器开始,一路走到头,直到被最后一个过滤器处理。

过滤器的实现方式:
在Gateway实现一个过滤器非常简单,只要实现GatewayFilter接口的默认方法就好!

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    // 随意发挥
    return chain.filter(exchange);    
}

这里面有两个关键信息:
ServerWebExchange:这是Spring封装的HTTP request-response交互协议,从中我们可以获取request和response中的各种请求参数,也可以向其中添加内容
GatewayFilterChain:它是过滤器的调用链,在方法结束的时候我们需要将exchange对象传入调用链中的下一个对象

过滤器的执行阶段:
不同于springcloud中上一代网关组件Zuul里对过滤器的Pre和Post的定义,
Gateway是通过Filter中的代码来实现类似Pre和Post的效果!
Pre和Post是指当代过滤器执行阶段,Pre是在下一个过滤器之前被执行,Post
是在过滤器执行过后再执行。我们在GatewayFileter也可以同时定义Pre和Post执行逻辑!!

Pre类型:
AddResponseHeaderGatewayFilterFactory,它可以向Response中添加Header信息:

@Override
public GatewayFilter apply(NameValueConfig config) {
	return (exchange, chain) -> {
        exchange.getResponse().getHeaders().add(config.getName(), config.getValue());
        return chain.filter(exchange);
    };
}

Post类型:
SetStatusGatewayFilterFactory,它在过滤器执行完毕之后,将制定的HTTP status返回给调用方!!

return chain.filter(exchange).then(Mono.fromRunnable(() -> {
		// 这里是业务逻辑
		}));   

这个过滤器的主要逻辑在then方法中,then是一个回调函数,在下级调用链路都完成以后再执行,因此这类过滤器可以看做是Post Filter

过滤器排座次:
在Gateway中我们可以通过实现org.springframework.core.Ordered接口,来给过滤器指定执行顺序,比如下面的代码实现了Ordered接口方法,将过滤器执行顺序设置为0:

@Override
public int getOrder() {
	return 0;
}                                                          
Pre

类型的过滤器来说,数字越大表示优先级越高,也就越早被执行。但对于Post类型的过滤器,则是数字越小越先被执行。

过滤器示例:
Header过滤器
这个系列有很多组过滤器,AddRequestHeader和AddResponseHeader,分别向Request和Response里加入指定Header。相应的RemoveRequestHeader和RemoveResponseHeader分别做移除操作,用法也很简单:

.filters(f -> f.addResponseHeader("who", "gateway-header"))
                                             

上面的例子会向header中添加一个who的属性,对应的值是gateway-heade

StringPrefix过滤器:
这是个比较常用的过滤器,它的作用是去掉部分URL路径。比如我们的过滤器配置如下:

.route(r -> r.path("/gateway-test/**")
             .filters(f -> f.stripPrefix(1))
             .uri("lb://FEIGN-SERVICE-PROVIDER/")
)        

假如HTTP请求访问的是/gateway-test/sample/update,如果没有StripPrefix过滤器,那么转发到FEIGN-SERVICE-PROVIDER服务的访问路径也是一样的。当我们添加了这个过滤器之后,Gateway就会根据“stripPrefix(1)”中的值截取URL中的路径,比如这里我们设置的是1,那么就去掉一个前缀,最终发送给后台服务的路径变成了“/sample/update”

PrefixPath过滤器:
它和StripPrefix的作用是完全相反的,会在请求路径的前面加入前缀

.route(r -> r.path("/gateway-test/**")
             .filters(f -> f.prefixPath("go"))
             .uri("lb://FEIGN-SERVICE-PROVIDER/")
)      

比如说我们访问“/gateway-test/sample”的时候,上面例子中配置的过滤器就会把请求发送到“/go/gateway-test/sample”。

RedirectTo过滤器:
可以把收到特定的状态码的请求重定向到一个特定的网址:
.filters(f -> f.redirect(302, “https://www.xxx.com/”))
上面的例子接收HTTP status code和URL两个参数,如果请求结果是404,则重定向到第二个参数指定的页面,这个功能也可以做统一异常处理,将Unauthorized或Forbidden请求重定向到登录页面。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/761375.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

最短路模型——AcWing 188. 武士风度的牛

最短路模型 定义 最短路模型是图论中的一个经典问题&#xff0c;旨在寻找从图中一个顶点到另一个顶点的路径&#xff0c;使得这条路径上的边&#xff08;或边的权重&#xff09;之和最小。这一模型在许多实际问题中有着广泛的应用&#xff0c;比如网络路由、地图导航、物流配…

AI绘画-Stable Diffusion 原理介绍及使用

引言 好像很多朋友对AI绘图有兴趣&#xff0c;AI绘画背后&#xff0c;依旧是大模型的训练。但绘图类AI对计算机显卡有较高要求。建议先了解基本原理及如何使用&#xff0c;在看看如何实现自己垂直行业的绘图AI逻辑。或者作为使用者&#xff0c;调用已有的server接口。 首先需…

Advanced slides插件无法预览幻灯片

advanced-slides的官方地址&#xff1a; MSzturc/obsidian-advanced-slides: Create markdown-based reveal.js presentations in Obsidian (github.com) 官方教程和文档&#xff1a; Advanced Slides Documentation (mszturc.github.io) 中文版也有博客翻译了&#xff1a;Ob…

[数据集][目标检测]桥梁检测数据集VOC+YOLO格式1116张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1116 标注数量(xml文件个数)&#xff1a;1116 标注数量(txt文件个数)&#xff1a;1116 标注…

51单片机第21步_将TIM0用作两个8位定时器同时将TIM1用作波特率发生器

本章重点讲解将TIM0用作两个8位定时器&#xff0c;同时将TIM1用作波特率发生器。 当定时器T0在方式3时&#xff0c;T1不能产生中断&#xff0c;但可以正常工作在方式0、1、2下&#xff0c;大多数情况下&#xff0c;T1将用作串口的波特率发生器。 1、定时器0工作在模式3框图&a…

【基础篇】第4章 Elasticsearch 查询与过滤

在Elasticsearch的世界里&#xff0c;高效地从海量数据中检索出所需信息是其核心价值所在。本章将深入解析查询与过滤的机制&#xff0c;从基础查询到复合查询&#xff0c;再到全文搜索与分析器的定制&#xff0c;为你揭开数据检索的神秘面纱。 4.1 基本查询 4.1.1 Match查询…

从手工作坊到智能工厂:APS与MES的升级之路

一、APS&#xff1a;制造业的中枢 APS&#xff08;AdvancedPlanningandScheduling&#xff09;&#xff0c;堪称制造业的数据接收和处理中枢&#xff0c;其借助前沿的算法与缜密的逻辑构建排程模型&#xff0c;全方位综合考量市场的多元需求、工厂的实际产能、物料的储备情况、…

Sentinel 采用的是什么限流算法?

引言&#xff1a;Sentinel 是一款由阿里巴巴开源的流量控制组件&#xff0c;提供了多种流控规则和限流算法&#xff0c;能够有效保护服务不被过载&#xff0c;同时实现服务的稳定运行。本文将深入探讨 Sentinel 所采用的主要限流算法&#xff0c;包括固定窗口计数器、滑动窗口计…

从0开始建SMARTFORMS表格

一、简介步骤 1、设置纸张的大小&#xff08;页格式&#xff09; 2、设置字体大小&#xff08;样式&#xff09; 3、设置表格模板 二、详细操作步骤 1、设置页格式 事务码&#xff1a;SPAD 参考操作&#xff1a;SAP Smartforms页格式创建与使用_sap 页格式-CSDN博客 SA…

【Altium】AD-焊盘介绍

【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 介绍PCB设计工具中焊盘的组成 2、 知识点 为元件创建封装时&#xff0c;焊盘都是不可获取的部分&#xff0c;一个完整的焊盘&#xff0c;包含了哪些部分&#xff0c;各自又是什么作用。 3、软硬件环境 1&#xff…

深度学习 --- stanford cs231学习笔记六(训练神经网络之权重的初始化与批归一化)

权重矩阵的初始化与批归一化 3&#xff0c;权重矩阵的初始化 深度学习所学习的重点就是要根据损失函数训练权重矩阵中的系数。即便如此&#xff0c;权重函数也不能为空&#xff0c;总是需要初始化为某个值。 3&#xff0c;1 全都初始化为同一个常数可以吗&#xff1f; 首先要简…

英飞凌TC3xx之DMA工作原理及应用实例

英飞凌TC3xx之DMA工作原理及应用实例 1 DMA的架构2 必要的术语解释3 DMA请求3.1 DMA软件请求3.2 DMA硬件请求3.3 DMA 菊花链请求3.4 DMA自动启动请求3.5 总结4 小结DMA是直接存储访问Direct Memory Access的简称。它的唯一职能就是在不需要CPU参与的情况下,将数据从源地址搬运…

go Channel原理 (二)

Channel 设计原理 不要通过共享内存的方式进行通信&#xff0c;而是应该通过通信的方式共享内存。 在主流编程语言中&#xff0c;多个线程传递数据的方式一般都是共享内存。 Go 可以使用共享内存加互斥锁进行通信&#xff0c;同时也提供了一种不同的并发模型&#xff0c;即通…

复兴社:凝聚多方力量,共促乡村繁荣

复兴社自成立以来&#xff0c;始终肩负着推动全国经济发展、实现共同富裕的重任。乡村振兴作为实现这一目标的重要途径之一&#xff0c;一直是复兴社的工作重点。在李忠平会长的领导下&#xff0c;复兴社通过联合政府、企业和社会各界的资源&#xff0c;共同推进乡村振兴&#…

基于STM32的智能门锁控制系统

目录 引言环境准备智能门锁控制系统基础代码实现&#xff1a;实现智能门锁控制系统 4.1 数据采集模块4.2 数据处理与分析4.3 控制系统实现4.4 用户界面与数据可视化应用场景&#xff1a;门锁管理与优化问题解决方案与优化收尾与总结 1. 引言 智能门锁控制系统通过使用STM32嵌…

Is ChatGPT a Good Personality Recognizer? A Preliminary Study?

ChatGPT是一个很好的人格识别者吗&#xff1f;初步调研 摘要1 介绍2 背景和相关工作3 实验3.1 数据集3.2 提示策略3.3 基线3.4 评估指标3.5 实现细节3.6 Overall Performance (RQ1)3.7 ChatGPT在人格识别上的公平性 (RQ2)3.8 ChatGPT对下游任务的人格识别能力&#xff08;RQ3&a…

Java 面试指南合集

JVM 篇 线程篇 springBoot篇 SpringCloud篇 待更新 黑夜无论怎样悠长&#xff0c;白昼总会到来。 此文会一直更新哈 如果你希望成功&#xff0c;当以恒心为良友&#xff0c;以经验为参谋&#xff0c;以当心为兄弟&#xff0c;以希望为哨兵。

行业分析---造车新势力之极氪汽车

1 前言 在之前的博客中&#xff0c;笔者撰写了多篇行业类分析的文章&#xff08;科技新能源&#xff09;&#xff1a; 《行业分析---我眼中的Apple Inc.》 《行业分析---马斯克的Tesla》 《行业分析---造车新势力之蔚来汽车》 《行业分析---造车新势力之小鹏汽车》 《行业分析-…

绘图黑系配色

随便看了几篇小论文&#xff0c;里面的黑配色挺喜欢的&#xff0c;虽然平时SCI系配色用的多&#xff0c;但看到纯黑配色与黑加蓝配色&#xff0c;那就是我最心上的最优style。

【JVM】JVM 内存结构

程序计数器 Cpu 要不停的切换执行线程&#xff0c;所以在切换回同一个线程的时候要知道程序执行到哪了&#xff0c;程序计数器&#xff08;PC 计数器&#xff09;&#xff0c;用来存储指向下一条指令的地址&#xff0c;也就是将要执行的代码。 程序的分支、循环、跳转、异常处…