【Spring Cloud Alibaba】(三)OpenFeign扩展点实战 + 源码详解

news2024/11/28 20:52:00

CSDN成就一亿技术人

系列目录

【Spring Cloud Alibaba】(一)微服务介绍 及 Nacos注册中心实战
【Spring Cloud Alibaba】(二)微服务调用组件Feign原理+实战


本文目录

  • 系列目录
  • 前言
  • 一、Feign扩展点配置
  • 二、OpenFeign扩展点配置
    • 1. 通过配置文件配置
      • 有效范围说明
      • 验证是否生效
    • 2. 通过Java Bean配置
      • 有效范围说明
      • 验证是否生效
    • 补充说明1. 日志级别
    • 补充说明2. 契约contract
    • 补充说明3. 编解码器
    • 补充说明4. 拦截器
    • 补充说明5. 配置Client
      • 1). 配置Client为Apache HttpClient
      • 2). 配置Client为OkHttp
    • 补充说明6. 配置GZIP压缩
    • 小结
  • 三、源码解读
    • 1. 注册流程
    • 2. 扩展点配置主逻辑
    • 3. 配置文件源头
    • 4. Java Bean配置源头
  • 最后


前言

书接上文,我们掌握了Feign的基本使用、核心原理,以及Spring Cloud Alibaba如何快速整合Feign,真的太简单了!你是不是觉得这样就够了?但在实际项目使用OpenFeign时,我们常常会遇到各种需求,需要用到它提供的扩展,例如日志分析、自定义统一拦截器、客户端组件配置、GZIP压缩等等,这也正是我接下来在本文中分享的内容:首先我会从原生Feign扩展点配置入手,然后进行OpenFeign扩展点配置实战,最后对OpenFeign是如何实现的进行了源码解读,内容很详细,Let’s go!


一、Feign扩展点配置

在上文,我们主要讲解了架构图的上部和下部,本文主要针对架构图中间扩展部分
在这里插入图片描述

Feign本身提供了很多扩展点,例如:

  • 日志级别logLevel
  • 契约contract
  • 客户端client
  • 超时设置options
  • 编码器encoder
  • 解码器decoder
  • 拦截器requestInterceptor

这些扩展点,我们在使用原生Feign时,可以通过Feign.Builder指定,最后再通过target生成动态代理类,完成Bean注册。
Feign.Builder

举个例子:

@Bean
public UserService userService() {
    return Feign.builder()
            .logLevel(Logger.Level.BASIC)
            .contract(new Contract.Default())
            .client(new Client.Default(null, null))
            .encoder(new Encoder.Default())
            .decoder(new Decoder.Default())
            .target(UserService.class, "http://demo-b");
}

二、OpenFeign扩展点配置

通过上文的OpenFeign实战,我们很容易搭建出Spring Cloud Alibaba微服务框架,并实现服务之间通过OpenFeign调用。如果还未看过上文的同学,建议先看上文:【Spring Cloud Alibaba】(二)微服务调用组件Feign原理+实战

我这里准备了3个Spring Cloud Alibaba微服务:demo-ademo-bdemo-c,之所以准备3个服务是为了验证配置是全局有效还是局有效!
OpenFeign扩展点Demo的3个服务

在OpenFeign中扩展配置项,可以通过配置文件Java Bean两种方式,接下来我们就配置试试看!

1. 通过配置文件配置

application.properties格式:

feign.client.config.{服务名}.{配置名} = {配置值} 

我们配置一些你可能用的上的扩展项,比如:日志级别配置契约配置超时配置编解码配置拦截器配置,如下:

# 日志级别配置
feign.client.config.default.loggerLevel = BASIC
# 契约配置
feign.client.config.default.contract = feign.Contract.Default
# 连接超时配置
feign.client.config.default.connectTimeout = 5000
# 读取超时配置
feign.client.config.default.readTimeout = 30000
# 编码器配置
feign.client.config.default.encoder = feign.jackson.JacksonEncoder
# 解码器配置
feign.client.config.default.decoder = feign.jackson.JacksonDecoder
# 拦截器配置, 是数组, 需要自定义RequestInterceptor
feign.client.config.default.requestInterceptors[0]=com.tiangang.demo.c.interceptor.MyFeignRequestInterceptor

有效范围说明

  • 全局生效:配置 {服务名}default ,如上面例子中所示
  • 局部生效:配置 {服务名}具体服务名
    例如,下面的配置仅对调用demo-b服务有效。
  feign.client.config.demo-b.loggerLevel = BASIC

验证是否生效

你知道如何快速验证吗?

挨个试?😏😏😏 教你一个简单有效的方法:

我使用demo-c发起调用,可以在启动demo-c 启动服务 时,构建 动态代理前 打断点查看Feign.Builder

即在FeignClientFactoryBean.loadBalance方法的调target之前打断点:
FeignClientFactoryBean.loadBalance打断点查看Feign.Builder

  • 配置后的Feign.Builder,确认已经按application.properties配置:

Feign.Builder查看调试属性-已配置

  • 如果未配置,默认Feign.Builder如下:

Feign.Builder查看调试属性-未配置

对于是全局还是局部有效,我是确认过的,因为不好演示,所以大家有兴趣可以自行验证确认!

2. 通过Java Bean配置

通过Java代码配置的话需要定义一个配置类,例如我命名为:FeignConfig,里面定义需要配置的@Bean,与上面配置文件的配置项保持一致!为了做区分,这里将编解码器改为Gson。

public class FeignConfig {
    // 日志级别配置
    @Bean
    public Logger.Level feignLoggerLevel() {
        return Logger.Level.BASIC;
    }
    // 契约配置
    @Bean
    public Contract feignContract() {
        return new Contract.Default();
    }
    // 超时配置
    @Bean
    public Request.Options options() {
        return new Request.Options(5000, 30000);
    }
    // 编解码器配置Jackson
    /*@Bean
    public Encoder encoder() {
        return new JacksonEncoder();
    }
    @Bean
    public Decoder decoder() {
        return new JacksonDecoder();
    }*/
    
    // 编解码器配置Gson
    @Bean
    public Encoder encoder() {
        return new GsonEncoder();
    }
    @Bean
    public Decoder decoder() {
        return new GsonDecoder();
    }
    // 拦截器配置
    @Bean
    public MyFeignRequestInterceptor myFeignRequestInterceptor() {
        return new MyFeignRequestInterceptor();
    }
}

有效范围说明

  • 全局生效(扫描到的所有服务),两种方式:
    • 1.在FeignConfig上加@Configuration注解(需要保证能扫描到)
    • 2.在启动类的@EnableFeignClients注解中配置defaultConfiguration
@EnableFeignClients(defaultConfiguration = FeignConfig.class) 
  • 局部生效(指定服务):在接口API的@FeignClient注解中配置
@FeignClient(value = "demo-b", configuration = FeignConfig.class)

验证是否生效

这里直接到FeignClientFactoryBean.loadBalance方法的target生成动态代理之前打断点查看:

  • Java Bean配置后的Feign.Builder
    Java Bean配置后的Feign.Builder

对于是全局还是局部有效,我是确认过的,因为不好演示,所以大家有兴趣可以自行验证确认!

补充说明1. 日志级别

Feign提供了4种日志级别

日志级别简单说明
NONE默认值,不记录日志
BASIC记录请求方法、请求URL、响应状态代码、执行时间
HEADERS在BASIC级别的基础上,记录请求和响应的header
FULL记录全部日志:请求和响应的header、body和metadata

注意: 若要正常输出日志,需要配置接口包路径的日志级别,我这里是com.tiangang.demo.api,所以 application.properties 配置:

# 格式:logging.level.{feign接口包路径}=debug/info...
logging.level.com.tiangang.demo.api=debug

在这里插入图片描述

补充说明2. 契约contract

在OpenFeign下,大部分情况下不需要配置contract,但如果老项目已经定义了大量的feign注解,那么就没必要再改成SpringMvc注解了,直接改contract是个好办法!

OpenFeign的默认contract是SpringMvcContract,即支持SpringMvc注解。

如果修改为feign.Contract.Default,测试时别忘了加feign注解,否则会编译报错。

补充说明3. 编解码器

使用Jackson,需要引入依赖:

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-jackson</artifactId>
</dependency>

使用Gson,需要引入依赖:

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-gson</artifactId>
</dependency>

Gsonapplication.properties配置:

feign.client.config.default.encoder = feign.gson.GsonEncoder
feign.client.config.default.decoder = feign.gson.GsonDecoder

Feign本身还提供了很多编解码器,需要的话可以直接用,如下图:
Feign源码:Decoder实现类

当然了,你也可以自定义编解码器!

补充说明4. 拦截器

拦截器是 非常有用的扩展点,是我们实现定制化需求的利器!

当我们需要统一处理Header、处理请求参数、处理响应结果时,就可以通过自定义拦截器处理。

Feign默认提供了Basic 认证拦截器,我们可以直接配置使用:

public class FeignConfig {
    @Bean
    public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
        return new BasicAuthRequestInterceptor("userName", "password");
    }
}

另外,我们也可以自定义 ,只需要实现接口RequestInterceptor

public interface RequestInterceptor {

  /**
   * Called for every request. Add data using methods on the supplied {@link RequestTemplate}.
   */
  void apply(RequestTemplate template);
}

例如,上面的例子我自定义实现的拦截器如下:

public class MyFeignRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        template.header("ACCESS_KEY", "9ZIpCT02u2ctppiXOzbpwBWMtRKPgxKe");
    }
}

例子的拦截器就是统一加了一个ACCESS_KEY的header,当你的调用需要统一加header时,就可以使用拦截器实现。当然,不仅用于加header!下面的GZIP压缩就是通过拦截器实现的!

补充说明5. 配置Client

除了上面提到的通用配置方式外,OpenFeign提供了专门的FeignAutoConfiguration,里面包含对Client等的配置,帮助我们快速配置Client。

在OpenFeign中,默认的Client是JDK原生的URLConnection,接下来,我们就实战 快速配置Apache HttpClientOkHttp

1). 配置Client为Apache HttpClient

  • 引入依赖
<!-- Apache HttpClient-->
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
</dependency>
<!-- Feign集成Apache HttpClient -->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>
  • 配置文件中启用

application.properties

feign.httpclient.enabled=true

参考源码: FeignAutoConfiguration.HttpClientFeignConfiguration
OpenFeign源码:FeignAutoConfiguration.HttpClientFeignConfiguration源码头部

验证已经生效:
Feign验证已配置Client为HttpClient

2). 配置Client为OkHttp

  • 引入依赖
<!-- okhttp -->
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
</dependency>
<!-- Feign集成okhttp -->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
</dependency>
  • 配置文件中启用

application.properties

feign.httpclient.enabled=false
feign.okhttp.enabled=true

参考源码: FeignAutoConfiguration.OkHttpFeignConfiguration
OpenFeign源码:FeignAutoConfiguration.OkHttpFeignConfiguration源码头部

验证已经生效:
Feign验证已配置Client为OkHttp

补充说明6. 配置GZIP压缩

在大数据量HTTP传输时,开启压缩可以有效节约网络资源,提升接口性能,我们可以配置 GZIP 来压缩数据,这也是OpenFeign通过自定义拦截器为我们实现的扩展功能。

application.properties

# 请求数据压缩
feign.compression.request.enabled=true
# 压缩类型
feign.compression.request.mimeTypes=text/xml,application/xml,application/json
# 启用压缩的最小大小(默认是2048),这里为了测试配置成1
feign.compression.request.minRequestSize=1
# 响应数据压缩
feign.compression.response.enabled=true

配置项参考源码: FeignClientEncodingProperties
OpenFeign源码:FeignClientEncodingProperties头部
压缩条件判断逻辑:

  • 请求 必须 有header:Content-Type ,并且在配置的mimeTypes
  • 请求 必须 有header:Content-Length,并且大于配置的minRequestSize

OpenFeign源码:GZIP压缩条件判断逻辑

我这里准备了一个POST请求,请求json,返回json,日志级别我改为了FULL验证已经生效:
OpenFeign:验证GZIP已生效

注意: 只有当Feign的Client 不是 okhttp3.OkHttpClient 的时候,压缩配置才会生效,因为请求和响应的源码中有要求!如下:

  • 参考源码: FeignContentGzipEncodingAutoConfiguration
    OpenFeign源码: FeignContentGzipEncodingAutoConfiguration

  • 参考源码:FeignAcceptGzipEncodingAutoConfiguration
    OpenFeign源码:FeignAcceptGzipEncodingAutoConfiguration

老方法,我们也可以打断点看下GZIP压缩的拦截器:
验证Feign的GZIP拦截器

小结

配置项application.propertiesJava配置对象
日志级别logLevelfeign.client.config.default.loggerLevel = BASIC@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.BASIC;
}
契约contractfeign.client.config.default.contract = feign.Contract.Default@Bean
public Contract feignContract() {
return new Contract.Default();
}
超时设置optionsfeign.client.config.default.connectTimeout = 5000
feign.client.config.default.readTimeout =30000
@Bean
public Request.Options options() {
return new Request.Options(5000, 30000);
}
编解码器encoder&decoderfeign.client.config.default.encoder = feign.jackson.JacksonEncoder
feign.client.config.default.decoder = feign.jackson.JacksonDecoder
@Bean
public Encoder encoder() {
return new JacksonEncoder();
}
@Bean
public Decoder decoder() {
return new JacksonDecoder();
}
拦截器requestInterceptors#是数组,可以按下标配置多个
feign.client.config.default.requestInterceptors[0]=
com.tiangang.demo.api.interceptor.MyFeignRequestInterceptor
@Bean
public MyFeignRequestInterceptor myFeignRequestInterceptor() {
return new MyFeignRequestInterceptor();
}
Client#配置为ApacheHttpClient, 别忘了引入依赖
feign.httpclient.enabled=true

#配置为OkHttp, 别忘了引入依赖
feign.httpclient.enabled=false
feign.okhttp.enabled=true
GZIP压缩#当Feign的Client 不是 okhttp3.OkHttpClient 的时生效。
# 请求数据压缩
feign.compression.request.enabled=true
# 压缩类型
feign.compression.request.mimeTypes=text/xml,application/xml,application/json
# 启用压缩的最小大小(默认是2048)
feign.compression.request.minRequestSize=2048
# 响应数据压缩
feign.compression.response.enabled=true

三、源码解读

请思考:如果让你来开发设计,你会在哪里做扩展点配置?
思索中

我们先跟进下 注册流程,看看能不能找出扩展点配置是在哪里配置的!

1. 注册流程

回顾上文OpenFeign的实战三步走:

  • 引入依赖:spring-cloud-starter-openfeign
  • 定义远程API接口加@FeignClient注解
  • 启动类加@EnableFeignClients注解

通过这三步走,我们可以断定OpenFeign的核心实现:肯定和@EnableFeignClients注解有关,因为没有其它入口了,这也是SpringBoot整合的惯用套路,所以我们快速跟踪一下主线流程,看它是如何将接口API生成的动态代理类:

  • FeignClientsRegistrar
    @EnableFeignClients上有@Import(FeignClientsRegistrar.class)注解,
    OpenFeign源码:EnableFeignClients
    FeignClientsRegistrar重写的registerBeanDefinitions方法里会扫描所有@FeignClient的接口,并将所有接口注册为FeignClientFactoryBean
    OpenFeign源码:FeignClientsRegistrar扫描@FeignClient注解的接口并注册
  • FeignClientFactoryBean
    FeignClientFactoryBean重写getObject方法,先通过feign方法获取到Feign.Builder,再根据FeignClient.url决定是否走负载均衡loadBalance,不管怎么走,最终都会调用Feign.Builder.target方法生成动态代理对象。
    OpenFeign源码:FeignClientFactoryBean.getObject和getTarget

2. 扩展点配置主逻辑

OK,根据注册流程,主线已经很清晰了,获取到Feign.Builder的地方,正是我们扩展点配置的好地方,实际也确实在这里,如下图:
OpenFeign源码:FeignClientFactoryBean.feign

configureFeign方法:
在这里插入图片描述

红框处就是扩展点配置的主逻辑,如果以application.properties为默认defaultToProperties=true,默认也是true,一般也不会改):

  • 1.配置Java Bean

  • 2.配置properties的default配置(全局)

  • 3.配置properties的当前服务配置(局部)

否则else就反过来!(后配置的优先级自然更高!

3. 配置文件源头

主逻辑中的FeignClientPropertiesproperties 就是application.properties配置文件项的源头,带有@ConfigurationProperties注解,如下图:
OpenFeign源码:FeignClientProperties

从这里就可以看出:具体每项配置是Map类型的config,它的key=服务名value=FeignClientConfiguration

所以在application.properties里配置,均为feign.client.config.{服务名}.{配置名}={配置值}

如果 {服务名} =default,即默认对所有服务有效!否则,仅对配置服务有效!

FeignClientConfiguration中全部可配置的属性如下图:
OpenFeign源码: FeignClientConfiguration中全部可配置的属性

4. Java Bean配置源头

Java Bean配置,主要在主逻辑configureUsingConfiguration方法,另外在构建builder时也算一处,一共有两处,优先级由低到高:

  • FeignClientFactoryBean.feign方法 - 构建
    这里配置必备Bean,下图这5个都有在FeignClientsConfiguration里配置缺省Bean,当然,如果你在指定的FeignConfig中加了自定义@Bean,就会以你配置的为准!
    OpenFeign源码: FeignClientFactoryBean.feign方法 - 构建
  • FeignClientFactoryBean.configureUsingConfiguration方法 - 配置
    主要在这里配置可选Bean,就是下图这些 builder. 设置的,当然,如果你在指定的FeignConfig中加了自定义@Bean,就会以你配置的为准!
    OpenFeign源码: FeignClientFactoryBean.configureUsingConfiguration方法 - 配置

最后

通过本文,我们对OpenFeign的扩展点配置进行了实战,并对源码进行了详细解读,如果你在项目中使用到了OpenFeign,相信这些扩展功能会让你在项目中使用得心应手。 另外需要说明:OpenFeign不仅可以用于微服务之间的调用,还可以用于调用第三方服务,所以应用非常广泛!
至此,OpenFeign的神秘面纱就被我们完全揭开了!
那么接下来,在Spring Cloud Alibaba家族中,还有一位主打高性能RPC调用的组件,就是由阿里巴巴公司开源的,后捐献给Apache 基金会的Dubbo,那么它到底有什么过人之处,会让很多公司从Feign转到Dubbo调用?这也是我计划将在下文分享的内容,如果感觉不错,欢迎订阅本专栏,后面还有更多的【Spring Cloud Alibaba】实战知识陆续放出。

关注我 天罡gg 分享更多干货: https://blog.csdn.net/scm_2008
大家的「关注❤️ + 点赞👍 + 收藏⭐」就是我创作的最大动力!谢谢大家的支持,我们下文见!


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

二维码数据压缩实践 | 使用python对二维码数据进行压缩 |不乱码,支持中文

当前二维码的应用越来越广泛&#xff0c;包括疫情时期的健康码也是应用二维码的典型案例&#xff0c;最近需要通过一张二维码显示较多文本数据&#xff0c;也就是对二维码数据进行压缩&#xff0c;使用CSDN搜索了半天居然没有能简单使用的代码&#xff0c;很多事例代码解决不了…

机器连接和边缘计算

以一种高效、可扩展的方式进行连接和边缘计算的结合&#xff0c;解决了在工业物联网应用中的机器数据集成问题。 一 边缘计算 边缘计算描述了由中央平台管理的数据分散式处理。边缘计算对于工业物联网而言非常重要。在许多应用程序中&#xff0c;由于数据量非常大&#xff0c;…

C++STL剖析(十)—— 位图(bitset)

文章目录1. 位图的介绍2. 位图的概念3. 位图的实现&#x1f351; 构造函数&#x1f351; 设置指定位&#x1f351; 清除指定位&#x1f351; 获取指定位的状态&#x1f351; 打印函数4. 总结1. 位图的介绍 在介绍位图之前先来看一道面试题吧 给 40 亿个不重复的无符号整数&…

【网络原理2】---TCP协议的格式

传输层重点协议TCP 协议TCP 协议段格式TCP内部的工作机制1. 确认应答2.超时重传TCP 协议 TCP 协议相对于 UDP 是复杂不少的。 在网络编程这里已经讲了 TCP 的特点&#xff1a; 有链接 可靠传输 面向字节流 全双工 可靠传输 是 TCP内部的机制&#xff0c;和编码关系不大&#x…

[oeasy]python0083_十进制数如何存入计算机_八卦纪事_BCD编码_Binary_Coded_Decimal

编码进化 回忆上次内容 上次 研究了 视频终端的 演化 从VT05 到 VT100从 黑底绿字 到 RGB 24位真彩色形成了 VT100选项 从而 将颜色 数字化 了 生活中我们更常用 10个数字 但是 计算机中 用二进制 日常计数的十进制数 是如何存储进计算机的呢?&#x1f914; 从10进制到2进…

Java学习笔记-03(API阶段-2)集合

集合 我们接下来要学习的内容是Java基础中一个很重要的部分&#xff1a;集合 1. Collection接口 1.1 前言 Java语言的java.util包中提供了一些集合类,这些集合类又称之为容器 提到容器不难想到数组,集合类与数组最主要的不同之处是,数组的长度是固定的,集合的长度是可变的&a…

思科网络部署,(0基础)入门实验,超详细

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a;小刘主页 ♥️每天分享云计算网络运维课堂笔记&#xff0c;努力不一定有收获&#xff0c;但一定会有收获加油&#xff01;一起努力&#xff0c;共赴美好人生&#xff01; ♥️夕阳下&#xff0c;是最美的绽放&#xff0…

如何让一起打拼的员工有持续的动力

我们的工作都要靠团队的每一个人努力&#xff0c;如何持续让老员工也能有持续的动力完成任务是我们非常重要的管理目标。 方法一&#xff1a;提供稀缺的学习机会。很多企业的培训都是针对新员工或者管理层的&#xff0c;容易让老员工意识不到自己应该学习&#xff0c;接触不到新…

Echarts 雷达图设置拐点大小和形状,tooltip后文字不居中对齐

第017个点击查看专栏目录Echarts的雷达图的拐点大小和形状是可以设置的&#xff0c;在series中设置symbol 相应的属性即可。 使用tooltip的时候&#xff0c;默认状态文字是居中对齐的&#xff0c;不好看。需要在tooltip属性中设置一下&#xff0c;如图所示&#xff0c;效果比较…

记录robosense RS-LIDAR-16使用过程4

一、时隔一个月&#xff0c;再次记录激光雷达的使用&#xff0c;一个月不碰生疏了好多&#xff0c;如鲠在喉&#xff0c;先来个基本操作熟悉一下找找感觉。连接在线雷达&#xff1a;https://github.com/RoboSense-LiDAR/rslidar_sdk/blob/main/doc/howto/06_how_to_decode_onli…

selenium--验证码识别,一文教会你回答面试官

相信大家在日常划水&#xff0c;培训&#xff0c;工作中都遇到这样的问题&#xff0c;验证码怎么处理&#xff1f;也有一些面试官会这么问。这里大致的说说&#xff0c;最常见的处理方式。1、万能验证码&#xff1a;所谓的万能验证码也就是找开发固定一个验证码&#xff0c;比如…

jenkins下配置maven

1. 先在jenkins服务器上安装maven 下载-解压-重命名-启动 [rootVM-0-12-centos local]# wget https://mirrors.aliyun.com/apache/maven/maven-3/3.9.0/binaries/apache-maven-3.9.0-bin.tar.gz [rootVM-0-12-centos local]# tar xf apache-maven-3.9.0-bin.tar.gz [rootVM-0…

嵌入式ARM设计编程(一) 简单数据搬移

文章和代码已归档至【Github仓库&#xff1a;hardware-tutorial】&#xff0c;需要的朋友们自取。或者公众号【AIShareLab】回复 嵌入式 也可获取。 一、实验目的 熟悉实验开发环境&#xff0c;掌握简单ARM汇编指令的使用方法。 二、实验环境 硬件&#xff1a;PC机 软件&am…

【招聘】永善县社会科学界联合会招办公室文秘人员2名

【招聘】永善县社会科学界联合会招办公室文秘人员2名 因工作需要&#xff0c;根据《永善县人力资源和社会保障局关于做好2021年公益性岗位开发管理的通知》(永人社发〔2020〕34号)文件要求&#xff0c;现面向社会公开招聘公益性岗位工作人员&#xff0c;现通告如下&#xff1a…

锐捷(十五)mpls vxn跨域optionc场景

一 实验拓扑二 实验需求ce1和ce2为两个分公司&#xff0c;要求两个分公司之间用mpls vxn 进行通信&#xff0c;组网方式是optionc。三 实验分析optionc在转发平面上有点难理解&#xff0c;有一些关键点需要注意&#xff0c;大家点击链接可以参考我上篇发过的一个文章&#xff1…

前端md5加盐加密

为什么需要加密 前端在进行用户登录时&#xff0c;密码的传输如果使用明文&#xff0c;在报文被拦截之后即可直接获取传输的数据&#xff0c;明文密码被拦截会十分危险&#xff0c;因此在传输密码前时常对密码进行加密。 MD5 MD5的作用是让大容量信息在用数字签名软件签署私…

植物大战 List——C++

这里写目录标题vector和stirng的细节对于stringlist的使用list的迭代器反向迭代器构造函数关于list::sort的排序uniquelist的底层模拟实现结点类的实现迭代器模拟实现list实现插入的实现迭代器失效inserterase析构函数拷贝构造赋值构造函数vector和stirng的细节 复习vector的深…

全网详细总结com.alibaba.fastjson.JSONException: syntax error, position at xxx常见错误方式

文章目录1. 复现问题2. 分析问题3. 解决问题4. 该错误的其他解决方法5. 重要补充1. 复现问题 今天在JSONObject.parse(json)这个方法时&#xff0c;却报出如下错误&#xff1a; com.alibaba.fastjson.JSONException: syntax error, position at 0, name usernameat com.aliba…

Web自动化测试——Junit5篇

文章目录一、相关依赖注入二、注解调用三、断言 Assert四、规定用例执行顺序五、高效参数化1&#xff09;单参数2&#xff09;多参数3&#xff09;文件获取参数4&#xff09;方法获取数据&#xff08;动态参数&#xff09;六、测试套件整活Junit 是一个面向 Java 语言的单元测试…

网络安全-协议爆破-xhydra

网络安全-协议爆破-xhydra 啥叫爆破呢&#xff0c;当你忘记密码了&#xff0c;一个一个去猜想的时候&#xff0c;这个东东就叫暴力破解 简称爆破&#xff0c;而且用程序的组合去一个一个试&#xff0c;时间问题&#xff0c;总有尝试到的那天 爆破前需求 也就是说满足了什么…