0%

curl 命令详解:命令行下的 HTTP 访问利器

curl 是一款功能强大的命令行工具,支持 HTTP、HTTPS、FTP 等多种协议,可用于发送 HTTP 请求、获取网页内容、调试接口等。本文将详细介绍 curl 的核心用法和常用参数,帮助你高效在命令行中进行网络交互。

基础用法:发起简单请求

1. 发送 GET 请求(默认)

直接指定 URL 即可发送 GET 请求,返回响应体内容:

1
2
# 获取百度首页内容
curl www.baidu.com

输出结果为网页的 HTML 源代码,适合快速查看简单接口的返回数据。

查看响应头:-i-I 参数

1. -i:显示响应头 + 响应体

1
curl -i www.baidu.com

输出示例:

1
2
3
4
5
6
7
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
...(响应头内容)...

<!DOCTYPE html>
...(响应体 HTML 内容)...
阅读全文 »

Spring Boot JAR 包结构详解:从内部组成到启动原理

Spring Boot 项目通过 spring-boot-maven-plugin 打包生成的 JAR 包,并非普通 Java JAR,而是可执行 JAR(Executable JAR)—— 其内部结构经过特殊设计,包含了应用代码、依赖库、启动器和配置信息,确保能通过 java -jar 直接执行。从 “目录结构解析→核心文件作用→启动流程关联” 三个维度,彻底讲透 Spring Boot JAR 包的内部逻辑。

Spring Boot JAR 包整体结构

首先,我们通过一个标准的 Spring Boot JAR 包解压后的目录结构,直观理解其组成:

springboot打成jar包的结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
demo-0.0.1-SNAPSHOT.jar  # Spring Boot 可执行 JAR
├─ BOOT-INF/ # 核心目录:存放应用代码和依赖
│ ├─ classes/ # 1. 应用编译后的 .class 文件和配置
│ │ ├─ com/ # 项目包结构(如 com.zhanghe.study.springboot)
│ │ │ └─ DemoApplication.class # 你编写的主程序类(含 main 方法)
│ │ ├─ application.yml # 应用配置文件(自定义配置)
│ │ └─ static/ # 静态资源(CSS/JS/图片,若存在)
│ └─ lib/ # 2. 项目依赖的第三方 JAR 库
│ ├─ spring-boot-1.5.9.RELEASE.jar # Spring Boot 核心依赖
│ ├─ spring-webmvc-4.3.13.RELEASE.jar # Web 依赖
│ ├─ mybatis-3.4.6.jar # 自定义依赖(如 MyBatis)
│ └─ ... # 其他所有依赖(Maven 引入的依赖都会打包到这里)
├─ META-INF/ # 3. 元信息目录:JAR 清单和依赖索引
│ ├─ MANIFEST.MF # 关键:JAR 清单文件(启动配置核心)
│ └─ maven/ # Maven 构建信息(可选,如 pom.xml 快照)
│ └─ com.zhanghe.study/demo/
│ ├─ pom.xml # 项目的 pom.xml 副本
│ └─ pom.properties # Maven 构建属性(如版本、groupId)
└─ org/ # 4. Spring Boot 启动器目录:内置启动工具类
└─ springframework/
└─ boot/
└─ loader/ # 启动器核心包
├─ JarLauncher.class # JAR 包启动器(Main-Class 指向此类)
├─ WarLauncher.class # WAR 包启动器(若打包为 WAR 则用此类)
└─ LaunchedURLClassLoader.class # 自定义类加载器(加载 BOOT-INF 资源)

这个结构的核心是 “分层存放”:将 “应用代码”“依赖库”“启动工具” 分离,既保证了可执行性,又便于管理资源。

核心目录详解:每个目录的作用

1. BOOT-INF/:应用与依赖的核心存放地

BOOT-INF 是 Spring Boot JAR 包的 “心脏”,所有与项目业务相关的内容都在这里,分为 classeslib 两个子目录。

阅读全文 »

搜索引擎核心概念解析:从索引到排序的核心逻辑

搜索引擎的核心功能是 “快速找到与查询相关的信息”,这一过程依赖于多个关键技术概念的协同作用。其中,倒排索引是数据结构基础,分词是处理输入的前提,停止词优化索引效率,排序则决定结果的相关性。以下是这些概念的详细解析:

倒排索引(Inverted Index):搜索引擎的 “字典”

倒排索引是搜索引擎最核心的数据结构,其设计颠覆了 “文档→词语” 的正向映射,转而建立 “词语→文档” 的反向映射,从而实现根据词语快速定位包含它的所有文档。

基本结构

倒排索引由两部分组成:

  • 词典(Term Dictionary):存储所有被索引的词语(去重后),通常按字母 / 拼音排序,便于快速查找。
  • 倒排列表(Posting List):每个词语对应一个列表,记录包含该词语的文档 ID,以及词语在文档中的位置、出现次数等附加信息。

示例

词语(Term) 倒排列表(文档 ID 及附加信息)
人工智能 [(1, 出现 3 次,位置 [5,12,20]), (3, 出现 1 次,位置 [8])]
机器学习 [(2, 出现 2 次), (3, 出现 5 次)]

核心作用

  • 快速检索:用户输入查询词后,搜索引擎通过词典定位到词语,再通过倒排列表直接获取所有相关文档,避免遍历全部文档。
  • 支持复杂查询:通过对多个词语的倒排列表进行交集(AND)、并集(OR)等运算,实现 “多关键词组合查询”(如 “人工智能 AND 应用”)。

优化方向

  • 压缩存储:倒排列表中的文档 ID 通常按顺序存储,可通过差值编码(如存储相邻 ID 的差值)减少存储空间。
  • 附加信息扩展:除文档 ID 外,可记录词语的TF-IDF 值(词频 - 逆文档频率)、在标题 / 正文中的出现位置等,用于后续排序。

分词(Tokenization):将文本拆分为 “有意义的单元”

分词是将原始文本(句子、段落)拆分为词语(Term) 的过程,是构建倒排索引的前提。不同语言的分词难度差异显著。

阅读全文 »

Netty 零拷贝机制深度解析:从内核原理到实践应用

零拷贝(Zero-Copy)是高性能网络编程的核心优化手段,其核心思想是减少数据在内存之间的不必要拷贝,从而降低 CPU 开销、提升程序性能。Netty 作为高性能 NIO 框架,通过多种机制实现了零拷贝,本文将从操作系统内核原理出发,详解零拷贝的实现方式及 Netty 中的具体应用。

零拷贝的底层基础:内核空间与用户空间

现代操作系统为保证安全性,将内存空间划分为内核空间用户空间,两者隔离且权限不同:

空间类型 权限范围 核心功能
内核空间 高权限(可直接访问硬件资源) 管理进程、内存、文件系统、网络等核心功能
用户空间 低权限(不可直接访问硬件) 运行用户应用程序,需通过系统调用访问内核

数据传输的天然屏障
用户程序无法直接操作硬件(如磁盘、网卡),必须通过内核作为中间层。例如,读取文件并发送网络数据时,数据需在用户空间与内核空间之间多次拷贝,这是传统 IO 性能瓶颈的根源。

传统 IO 的数据拷贝问题

以 “读取本地文件并通过网络发送” 为例,传统 IO(如 Java 的 FileInputStream + Socket)的流程如下:

完整步骤解析

  1. 第一次拷贝:DMA 引擎将磁盘文件数据拷贝到内核缓冲区(内核空间),触发用户态 → 内核态上下文切换(read 系统调用)。
  2. 第二次拷贝:CPU 将内核缓冲区数据拷贝到用户缓冲区(用户空间),触发内核态 → 用户态上下文切换(read 调用返回)。
  3. 第三次拷贝:CPU 将用户缓冲区数据拷贝到Socket 缓冲区(内核空间),触发用户态 → 内核态上下文切换(write 系统调用)。
  4. 第四次拷贝:DMA 引擎将 Socket 缓冲区数据拷贝到网卡协议栈,无需 CPU 参与。
  5. 最后切换write 调用返回,触发内核态 → 用户态上下文切换。

传统数据读写

性能瓶颈

  • 4 次数据拷贝:其中 2 次涉及 CPU 拷贝(第二次和第三次),消耗计算资源。
  • 4 次上下文切换:用户态与内核态切换耗时(每次切换约 1~10 微秒),高并发场景下累积开销巨大。
阅读全文 »

ConcurrentSkipListMap:基于跳表的高效并发有序映射

ConcurrentSkipListMap 是 Java 并发包中提供的支持并发访问的有序映射,底层基于跳表(SkipList) 数据结构实现。它结合了跳表的高效查找性能和并发控制机制,在保证线程安全的同时,提供了接近平衡树的 O (logn) 时间复杂度操作。本文将深入解析其底层结构、核心原理及并发实现。

跳表(SkipList):随机化的数据结构

跳表是一种用于快速查找的有序数据结构,通过在链表基础上增加多层索引,实现了高效的插入、删除和查询操作。其核心思想是 “以空间换时间”,通过随机化策略决定节点的层级,减少查询时需要遍历的节点数量。

跳表的核心特性

  • 多层结构:由多个层级的链表组成,最底层(Level 0)包含所有元素,上层链表是下层的 “稀疏索引”;
  • 有序性:每一层链表中的节点按 key 有序排列(升序或自定义排序);
  • 层级规则:若一个节点出现在 Level i,则它一定出现在所有 Level < i 的层级中;
  • 随机化:节点的层级通过随机算法生成(通常以 1/2 概率递增层级),避免最坏情况。

跳表示意图

跳表搜索

1
2
3
4
Level 3:  1 --------------------------> 7  
Level 2: 1 ---------> 3 ------------> 7
Level 1: 1 ----> 2 ----> 3 ----> 5 -> 7
Level 0: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 (原始链表)

查询过程(如查找 5):

  1. 从最高层(Level 3)开始,1 的下一个节点是 7(>5),下降到 Level 2;
  2. Level 2 中 3 的下一个节点是 7(>5),下降到 Level 1;
  3. Level 1 中 3 的下一个节点是 5,找到目标,共遍历 4 个节点(远少于 Level 0 的 5 个)。

ConcurrentSkipListMap 的底层结构

ConcurrentSkipListMap 通过三个内部类构建跳表结构:Node(数据节点)、Index(索引节点)和 HeadIndex(头索引节点)。

核心内部类

Node:存储键值对的基础节点
阅读全文 »