当前位置: 首页 > news >正文

客户端开发八股

java垃圾回收机制

概念

  • Java的垃圾回收机制是JVM的自动内存管理机制,是一个运行在JVM后台的守护进程,由GC(Garbage Collection)实现。主要负责识别和回收不被使用的对象

  • Java的回收机制是一个低优先级的进程,它可以根据内存的使用情况动态的调整其优先级,这是为了尽量避免频繁的进行垃圾回收,造成对CPU资源的浪费

原理

  • 垃圾回收机制通过对象的可达性算法(引用链法)分析来判断对象是否在被使用,如果一个对象不再被引用,那它就被认为是无用的,可以被回收的。

    可达性算法:又被称为“根可达算法”、“引用链法”。主要原理是以GC Roots(根)为起点,从起点开始往下寻找,搜索到的对象被判定为存活。如果有对象数据,但是此对象和根节点没有相连(即无法从任何一个根节点到达此对象,根不可达),那么此对象会被判为不可用,会在本次GC时被清除。

  • 垃圾回收主要针对空间和方法区进行。

垃圾回收器的选择

  • Serial Collector:串行垃圾收集器,Serial GC是一种基于标记-整理和复制算法的垃圾回收器,单线程执行GC操作,适用于客户端应用。

新生代和老年代怎么回收

在Java中,垃圾回收(Garbage Collection, GC)是自动管理内存的一个重要机制。Java堆内存通常被划分为几个不同的区域:新生代(Young Generation)老年代(Old Generation)**和永久代/元空间(Permanent Generation/Metaspace)

新生代的回收

新生代主要用于存放新创建的对象。它进一步被划分为三个部分:Eden区和两个Survivor区(通常称为From和To)。对象首先分配在Eden区,当Eden区满时,会触发一次Minor GC(也称为Young GC)。

当伊甸区再次满了,会再次触发Minor GC操作,将伊甸区和Survivor区(From区)的存活对象复制到另一个Survivor区(To区)

  • 如果某些对象已经经历了多次GC仍然存活,则它们会被晋升(promoted)到老年代。

老年代的回收

  • 当老年代的空间不足时,会触发Major GC或Full GC(取决于JVM实现和配置)。这些回收可能涉及整个堆(包括新生代和老年代)。

  • 老年代的垃圾回收通常采用标记-清除(Mark-Sweep)或者标记-整理(Mark-Compact)算法。前者可能会导致内存碎片化,而后者则会压缩堆中的对象以消除碎片。

为什么新生代不用标记整理算法

  1. 新生代对象多为短期存在,适合使用更高效的复制算法;
  2. 标记整理执行成本较高,因为它不仅需要标记所有存活的对象,还需要对这些对象进行重新定位和压缩,这在新生代这种大部分对象都是临时的情况下显得没有必要且低效。

哪些可以作为gc roots的?

在Java的垃圾回收机制中,GC Roots是指一系列被虚拟机直接引用的对象集合。垃圾收集器会从这些根节点开始遍历对象图,标记所有可达的对象,并回收那些不可达的对象(即被视为“垃圾”的对象)

  1. 虚拟机栈中的引用对象
  2. 方法区的静态成员变量和常量引用
  3. native中引用的对象
  4. 活跃线程
  5. 同步锁持有的对象
  6. JVM内部数据结构

java的四种引用类型

  1. 强引用:正常new一个对象就是强引用,只有在指向null的时候才会被GC回收

  2. 软引用:使用SoftReference修饰的对象被称为软引用,只有在内存空间不足的时候才会被回收,常用于缓存

  3. 弱引用:使用WeakReference修饰的对象被称为弱引用,指向的对象遇到GC就会被回收内存,用于ThreadLocal防止内存泄漏。

    通过使用弱引用作为 ThreadLocal 的键,可以确保当没有任何强引用指向某个 ThreadLocal 实例时,它可以被垃圾回收器回收,从而减少了由于 ThreadLocal 导致的内存泄漏风险。

  4. 虚引用:使用 PhantomReference 修饰,虚引用是在JVM中创建一个对象指向外部存储空间的一片缓冲区(Direct by buffer),使得JVM能直接操作到外部的存储空间

ThreadLocal 的作用是什么,怎么实现的,内存泄漏

作用

ThreadLocal 利用每个线程拥有独立的 ThreadLocalMap 来实现线程级别的数据隔离,只有在线程内才能获取到对应的值,线程外则不能访问

.1 原理

ThreadLocal并不是一个Thread,而是Thread的局部变量

  • 每个线程都拥有自己的 ThreadLocal 实例,该实例内部维护了一个 ThreadLocalMap 对象。
  • ThreadLocalMap 是一个散列表(哈希表),用于存储线程局部变量的值,其中的每个元素是一个键值对,键为 ThreadLocal 实例,值为对应线程的局部变量。
  • 当通过 ThreadLocal 获取或设置值时,首先会根据当前线程获取对应的 ThreadLocalMap 对象,然后使用 ThreadLocal 实例作为键来查找对应的值。
  • 每个线程独立维护自己的数据,不同线程之间的数据互不干扰,从而实现了数据在线程之间的隔离。

.2 实现方式

  1. ThreadLocal 实例本身是一个强引用,而与每个线程关联的局部变量则是弱引用。当线程被回收时,对应的局部变量也会被自动回收。防止内存泄漏
  2. 当调用 ThreadLocalset() 方法时,实际上是将传入的值与当前线程关联起来,并存储到当前线程的 ThreadLocalMap 中。
  3. 当调用 ThreadLocalget() 方法时,实际上是从当前线程的 ThreadLocalMap 中根据 ThreadLocal 实例查找对应的值并返回。如果没有找到,则返回 null 或指定的默认值。
  4. 在多线程环境下,由于每个线程都有自己独立的 ThreadLocalMap,因此每个线程可以独立地读取和修改自己的局部变量,而不会影响其他线程的数据。

客户端发起的每次请求都是一个单独的线程

ThreadLocal常用方法

  • public void set(T value) 设置当前线程的线程局部变量的值
  • public T get() 返回当前线程所对应的线程局部变量的值
  • public void remove() 移除当前线程的线程局部变量

描述一下微服务思想

把一个大型的单个应用程序和服务,拆分为数个甚至数十个的互联服务,每一个服务都是一个迷你应用。

每一个服务会给其他服务提供 REST API,但是各个微服务之间的 直接调用 是一个不小的网络负担,并且很麻烦,一般都会在 N 个服务添加一个代理或者叫 API Gateway (网关),一般用 Nginx 实现

主键索引和唯一索引的区别

主键索引

  • 唯一性:主键索引确保每一行数据在其主键列上都是唯一的,且不允许NULL
  • 聚簇索引:创建表时指定的主键会自动创建一个聚簇索引(在InnoDB存储引擎中)。这意味着表中数据是按照主键顺序物理存储的,这有助于提高某些查询的性能。
  • 单一性:一个表只能有一个主键,可以由单个字段组成,也可以由多个字段共同组成复合主键。

唯一索引

  • 唯一性:确保每一行数据在其主键列上都是唯一的,防止重复的值出现,但它允许其中的列包含NULL值
  • 可选性:与主键不同,一个表可以拥有多个唯一索引。
  • 非聚簇索引:除非特别指定,否则唯一索引通常是非聚簇的。也就是说,它们不会影响数据在磁盘上的物理存储顺序,而是通过单独的索引来保证数据的唯一性。
  • 灵活性:唯一索引不仅可以用在单个字段上,还可以用在组合字段上

聚簇索引和非聚簇索引的区别,覆盖索引

聚簇索引

  1. 聚簇索引是一种物理上重新组织表数据的方式,在聚簇索引中,表中的数据按照索引的顺序进行存储
  2. 一个表中只能有一个聚簇索引
  3. 聚簇索引的叶子节点包含了实际的数据行
  4. 适用于范围查找和排序操作

非聚簇索引

  1. 非聚簇索引是一种单独存储索引数据的方式
  2. 一个表中可以有多个非聚簇索引
  3. 非聚簇索引的叶子节点不包含实际的数据行,而是包含了指向相应数据行的指针
  4. 适用于等值查询

覆盖索引

覆盖索引是指一个索引包含了查询所需要的所有列的数据,这样MySQL就可以直接从索引中获取数据,而不需要进一步访问数据行。

项目中的redis和mysql怎么保证数据一致

  1. 读写分离和最终一致性

    对于某些应用,允许一段时间的数据不一致性,也就是我们追求的是”最终一致性“,在读取时优先从 Redis 获取数据,如果 Redis 中没有,则回退到 MySQL 查询,并将结果更新到 Redis。

  2. 异步检查与修复机制

    定期检查Redis和Mysql中的数据是否一致,并在发现不一致时进行修复。这可以通过后台任务或定时调度器来实现。

redis的大key和热key问题

  • 大key问题:Redis存储的单个key中对应的value过大(字符串体积过大,或者列表/哈希表/集合/有序集合等类型的元素数量过多)。这类key会显著影响Redis的性能和稳定性。因为Redis时单线程的(处理客户端的请求时),处理大key操作会占用主线程的时间,影响其他请求的响应速度;

  • 热key问题:某个瞬间有大量的请求去访问Redis上的某个固定的的key,导致缓存击穿,请求都打到DB上,压垮了缓存服务和DB服务,从而影响到应用服务的可用性;高频访问的单个key,其请求量远高于其他key

    在服务端读数据进行访问时,往往会对数据进行分片切分(Redis的哈希槽),此过程中会对某一个Redis节点主机Sever上对应的key进行访问,当访问超过该节点Sever的极限时,就会导致热key问题的发生。

大key解决方案

  • 找出大key

    • 使用Redis的命令行工具redis-cli中的–bigkeys参数,扫描Redis中的所有key,它会遍历整个键空间然后返回每个数据类型中的最大的key的信息;
    • 使用Redis RDB Tools开源工具进行分析
    • 可观测性分析,跟踪Redis的性能指标
  • 找到后,分析:大key是否为业务需要

    • 不是,通过业务逻辑的优化来处理这个问题
    • 检查程序BUG,看看是不是代码的问题,导致key的大小不正常
  • 解决方案

    • 在业务设计的初期就避免大key问题,仅仅缓存必要的数据字段

    • 数据拆分:把大key分片成小key进行存储

      数据拆分可能会导致部分写问题,在设计初期,可以给value加上一个版本号,以进行一致性检查,如果有一个版本号没对上,就回源,重新读取,然后重新加载并尝试写入

    • 换个数据结构

    • 合理的清理

      • 低峰期删除
      • 分批定时定量删除
      • 异步删除,使用unlink命令

热key解决方法

  • 监控发现

    • 凭借业务经验对热key进行预测
    • 业务侧自行监控和收集
    • 使用redis自带的命令
      • -minitor命令,这个命令可以实时抓取redis服务器接收的命令,统计出热key
      • 分析工具,redifaina
      • -hotkeys参数
      • Daas平台查看热keyd的分析和监控
  • 解决方案

    • 本地存储(多级缓存):在应用端(客户端)对热key添加本地缓存,减少对Redis的直接访问

      • 二级缓存:发现热key后将其加载到系统的JVM中,针对这种热key请求,会直接从本地缓存中读取,而不会直接请求Redis

      • 然而对缓存强一致的业务来说,需要花费更长的精力保证分布式缓存一致性上

        Hermes-SDK来保证缓存的一致性

    • 将热key分散到不同的服务器上

      • 在多个redis节点上,都备份一份,当有热key请求,在有备份的redis上随机选一台进行访问取值,返回数据
    • **热key拆分:**将热key拆分成多个子key,通过哈希表或者随机后缀的方式分散到不同节点,但是要保证数据的一致性

    • 读写分离:对热key启用速写分离,将读请求分发到从节点,但是Redis集群模式下从节点不分担读请求

    • 缓存永不过期+异步更新:对热key不设置过期时间,通过后台任务定期更新缓存,避免缓存击穿

    • 使用更高效的数据结构

缓存击穿,缓存穿透和缓存雪崩

缓存穿透

客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会访问数据库。导致DB的压力瞬间变大而卡死或者宕机。

解决方案:

  1. 缓存空对象:

  2. 布隆过滤器:在客户端与Redis之间加了一个布隆过滤器,对请求进行过滤。

  3. 增强 id 的复杂度,避免被猜测 id 规律

缓存击穿

缓存击穿问题也叫热点Key问题,就是⼀个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击。

解决方案:

  1. 互斥锁:并不是所有的线程都有 “ 资格 ” 去访问数据库,只有持有锁的线程才可以对其进行操作。可能出现相互等待的情况。
  2. 逻辑过期:不设置TTL

缓存雪崩

缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。

解决方案:

  1. 给不同的Key的TTL添加随机值
  2. 利用Redis集群提高服务的可用性
  3. 给业务添加多级缓存:请求到达浏览器,nginx可以做缓存,未命中找Redis,再未命中找JVM,最后到数据库

假如有一个redis集群,一个节点在中国,一个节点在美国,通信延迟很高,一个大key分片存在在这个集群中,中国节点向美国节点同步数据时有很多数据没有传输成功,怎么办

  1. 优化数据结构

    • 减少单个key的大小,将大数据集再次分割成多个较小的部分
    • 使用批量操作:利用Redis支持的批量操作来减少命令往返次数。
  2. 采用异步复制策略

    • 异步复制:确保主从复制是异步进行的,而不是同步等待确认。这可以减少因网络延迟导致的操作超时或失败。
    • 重试机制:实现数据同步失败后的自动重试逻辑,特别是针对网络不稳定情况下的临时性错误。
  3. 增加缓冲区或队列

    • 本地缓存:在中国节点上设置一层本地缓存,用于暂时存放需要同步到美国节点的数据,直到网络状况允许时再进行同步
    • 消息队列:使用消息队列作为中介,将需要同步的数据先放入队列中,然后由消费者按照优先级或顺序处理这些数据的同步任务。
  4. 调整Redis配置参数

    • timeout 设置:适当增加客户端空闲超时时间(timeout),以适应较长的网络延迟。
    • repl-timeout:对于主从复制场景,可以考虑增大repl-timeout值,给予更多的时间完成数据同步。

Redis是使用什么机制保证他快

  1. 内存存储
  • Redis的数据是存储在内存中,避免了磁盘 I/O 操作带来的延迟

  • 虽然Redis是基于内存存储的,但是也提供了两种主要的持久化策略:RDB和AOF

    持久化策略是指内存中的数据保存到磁盘中的方法

    RDB:一种快照机制,在指定的时间间隔生成当前Redis的一个完整备份文件

    AOP:记录了每个写操作命令(如 SET、DEL 等),这些命令会被追加到 AOF 文件末尾。Redis 可以在重启时重新执行这些命令来恢复数据状态。

  1. 单线程模型
    • Redis采用单线程处理客户端请求(I/O和后台任务除外),基于事件循环机制,避免了多线程中的上下文切换开销和竞争问题
    • Redis通过异步I/O模型,可以搞笑处理大量并发连接而不阻塞主进程
  2. 高效的数据表示
    • 提供五种不同类型的value,减少内存访问
    • O(1)操作,很多命令例如GET,SET,LPUSH等都是常数时间复杂度
  3. 主从复制与分片
    • 通过主从复制,可以实现读写分离,同时分片可以将key分散到不同的节点上,进一步提高了吞吐量
  4. 过期键删除策略
    • Redis不会立即删除过期的键,而是采用惰性删除(即访问的时候才检查是否过期),并且采用周期性的主动清理避免过期键过多
  5. 缓存淘汰算法
    • Redis提供了几种缓存淘汰策略:LRU最近最少使用等

Redis怎么保证每个请求都耗时差不多的时间

  1. 限制最大内存使用,设置合理的maxmermory
  2. 启用慢查询日志功能,记录超过指定阈值的命令执行时间,便于分析和优化潜在的性能瓶颈。
  3. 合理配置连接超时、命令执行超时等参数,防止长时间未完成的操作影响整个服务的响应时间。
  4. 分布式架构下的负载均衡:在集群模式下,通过良好的分区策略和负载均衡机制,确保各个节点的工作负荷相对均衡,避免某些节点成为性能瓶颈。

Mysql底层的数据结构?为什么用B+树,如果在内存中,B树和B+树的查询效率怎么样

MySQL 底层的数据结构主要体现在其存储引擎的设计上,常用的三种存储引擎有InnoDB(默认),MyISAM,Memory

  • InnoDB支持事务(支持错误回滚),MyiSAM不支持
  • MyiSAM适合查询和插入为主的应用
  • InnoDB支持外键,MyiSAM不支持

对于最常用的InnoDB存储引擎,其使用的数据结构是B+树,B+树是一种特殊的B树,特殊的是其非叶子节点不存数据,叶子节点会通过左右的指针进行关联,并且叶子节点中的数据已经排好序了

  • B+树是一种平衡树,它允许快速地进行查找、顺序访问、插入和删除操作。由于其高扇出特性(每个节点可以有多个子节点),B+树的高度通常很低,这使得查找非常快。
  • 在B+树中,所有叶子节点都通过指针相互连接,这样有利于实现范围查询和排序等功能。

MyISLAM存储索引实现(非聚簇索引,也是用B+树)

MyISAM的索引文件和数据文件是分离的(非聚簇索引:索引和数据不在同一个文件中),B+树的叶子节点存储的不是数据,而是磁盘的索引地址,当查找到叶子节点的数据的时候,还要多一次磁盘空间的查找

InnoDB的存储引擎实现(聚簇索引)

表数据文件本身就是按照B+树组织的一个索引结构文件,叶节点包含了完整的数据记录,

每个表只能有一个聚簇索引,因为数据只能用一种方式排序

为什么建议InnoDB表必须建主键,并且推荐使用整型的自增主键?

  1. 提高查找效率,因为数据是按照主键排序存储的,可以减少磁盘I/O操作
  2. 维护数据一致性,主键的存在保证了每条记录的一致性,有效避免了数据重复问题
  3. 相比于其他字符串或者更复杂的类型,整数类型的存储空间更小,节省了存储空间,并且整型的比较效率更高
  4. 自增主键意味着写入操作通常是顺序的,减少了对现有页的分裂操作,较少了并发写入时可能发生的锁竞争情况

为什么非主键索引(辅助索引)结构叶子节点存储的是主键值?

  1. 除了聚簇索引之外的所有索引都是辅助索引。与聚簇索引不同,辅助索引的叶子节点并不包含行记录的全部数据,而是包含该行的主键值。这意味着,要通过辅助索引访问完整的行数据,通常需要进行两次查找:第一次是在辅助索引中找到对应的主键值,第二次是通过这个主键值在聚簇索引中查找相应的行数据。

延时双删怎么实现

延迟双删(Delay Double Delete)通常用于解决数据在缓存和数据库中不一致的问题。

实现过程:

  1. 删除Redis中的缓存数据

    在这个过程中可能会有并发线程检测到缓存不存在,于是去查询数据库,并将旧数据写回缓存。

  2. 更新数据库中的数据

  3. Thread.sleep(N) 让当前线程休眠一段时间N

时间太短,并发线程可能还没有完成“查数据库 + 写缓存”这个动作;

时间太长,用户体验感差并且可能会出现脏读

  1. 再次删除Redis中的缓存数据,删除“可能被写入的旧缓存”

再次删除是为了让并发线程有机会完成“查数据库 + 写缓存”的动作,然后再通过第二次删除清除可能写入的旧缓存,从而提升缓存与数据库之间的一致性。

优化延时双删

  • 使用 消息队列异步刷新缓存

将数据库写操作与缓存删除操作解耦,通过消息队列异步通知缓存服务进行更新或删除,从而避免并发问题和缓存污染。

  • 使用 分布式锁 控制更新流程

  • 使用 Canal / Binlog 监听数据库变更,异步更新缓存

  • 使用 TTL + Cache Aside Pattern 结合策略

MySQL 是如何具体实现 ACID 的

MySQL 实现 ACID 特性的方式依赖于其存储引擎,特别是 InnoDB 存储引擎。

  • 原子性 依靠 Redo 和 Undo 日志;
  • 一致性 依赖于数据库对象定义的规则以及事务本身的特性;
  • 隔离性 利用了锁和 MVCC 技术;
  • 持久性 则通过 Redo Log 和 Doublewrite Buffer 等手段保障。

bin log和redo log

binlog和redolog都是用来记录数据库数据变更操作的日志

  1. 使用场景不同
  • binlog主要进行数据备份、数据恢复和主从集群的数据同步

  • redolog主要用来实现Mysql数据库的事务恢复(数据库出现崩溃,redolog课时把未提交的事务回滚,已提交的事务持久化)和保证事务的ACID特性

ACID:原子性、一致性、隔离性、持久性

  1. 记录信息不同
  • binlog记录的时数据库的逻辑变化,提供三种日志格式,分别是statement、row以及mixed。

  • redolog记录的是物理变化,也就是数据页的变化

  1. 记录时机不同
  • binlog是在执行SQL语句的时候,在主线程生成逻辑变化,写入到磁盘里面。所以它是语句级别的记录方式
  • redoLog是在InnoDB存储引擎层面的操作,它是在MySQL后台线程中去生成,并且写入到磁盘中的。所以它是事务级别的记录方式。一个事务操作完成之后才会被写入到redo log里面。

同步/异步IO,阻塞/非阻塞IO是什么,区别是什么

HashMap的put过程

为什么重写hashcode的同时重写equals,举出场景反例

拥塞控制

ZSet的原理,底层数据结构,跳表原理和流程

Sping

1. Spring核心是什么

Spring是一个开源框架,是一个IOC和AOP的容器框架

  • IOC:控制反转

  • AOP:面向切面编程

  • 容器:包含并管理应用对象的生命周期

2. Spring优势

  • Spring通过DI、AOP等来简化企业级java开发
  • Spring的IOC容器降低了业务对象替换的复杂性,提高了组件之间的解耦
  • Spring中的AOP支持允许一些通用任务如安全、事务、日志等进行集中式处理,从而更好的提高了复用

3. 谈谈对Spring IOC的理解、原理与实现

控制反转:原来的对象是由使用者来进行控制,有了Spring之后,可以把整个对象交给Spring来帮我们进行管理

通过DI(依赖注入)来实现,把对应的属性的值注入到具体的对象中,例如@Autowired注解

容器:存储对象,使用map结构来存储,在spring中一般存在三级缓存,singletonObjects存放完整的bean对象,

整个bean的生命周期,从创建到销毁的过程全部都是由容器来管理

spring中的bean都是通过反射的方式生成的,同时其中包含了很多的扩展点,比如最常用的对BeanFactory的扩展,对bean的扩展,除此之外,IOC中最核心的也就是填充具体的bean的属性和生命周期

4. Springboot自动配置原理

Spring IOC底层实现

bean的生命周期

线程间通信方式

  1. 全局变量方式

属于同一个进程的各个线程共享操作系统分配该进程的资源,故解决线程间通信最简单的一种方法是使用全局变量。

  1. 消息传递方式

应用程序的每个线程都有自己的消息队列,可以通过操作系统来实现从一个线程向另外一个线程发送消息(通过管道,信号量或者共享内存等方式)

  1. 参数传递方式

主线程在创建子线程时,可以通过传给线程函数的参数和其通信。所传递的参数是一个32位的指针,该指针不但可以指向简单的数据,而且可以指向结构体或类等复杂的抽象数据类型。

  1. 线程同步法

例如有两个线程,线程A写入数据,线程B读出线程A准备好的数据并进行一些操作。这种情况下,只有当线程A写好数据后线程B才能读出,只有线程B读出数据后线程A才能继续写入数据,这两个线程之间需要同步进行通信。

线程的内存区域是什么划分的

  1. 线程独有的内存区域包括程序计数器、虚拟机栈和本地方法栈,这些区域随着线程的创建而创建,随线程的结束而销毁。
  2. 线程共享的内存区域包括堆和方法区,它们在整个JVM生命周期内存在,除非发生垃圾回收或类卸载等情况才会释放部分空间。

https是对称加密还是非对称加密

  • 非对称加密:非对称加密使用一对密钥——公钥(Public Key)和私钥(Private Key)。公钥可以公开分享给任何人用于加密消息,而私钥则由持有者保密,仅用于解密收到的信息。用于安全地交换对称加密所需的会话密钥。
  • 对称加密:使用相同的密钥进行加密和解密操作,则用于后续的大规模数据传输,因为它更加高效。

在建立连接初期,客户端与服务器之间会使用非对称加密技术来交换会话密钥。一旦会话密钥被安全地交换后,客户端和服务器就会使用这个共享的秘密密钥来进行高效的加密和解密操作,这就是对称加密。

http有过很多版本,有了解过吗

  • HTTP/0.9 :只支持Get方法,不支持多媒体内通的MIME类型、各种HTTP首部、版本号等。

  • HTTP/3.0 :超文本传输协议的最新版本,基于 QUIC(Quick UDP Internet Connections) 协议构建。

    谷歌推出的一套基于UDP的传输协议,目的是保证可靠性的同时降低网络延迟

依赖注入的底层原理

Spring的依赖注入底层原理主要是基于Java反射机制和BeanFactory实现的。

Spring的依赖注入底层原理的核心就是BeanFactory中的createBean()方法,该方法通过反射机制实例化Bean对象,并完成属性的注入和初始化操作,最终将实例对象注册到容器中,以便于后续的使用。

具体的实现分为以下几个步骤:

  1. 扫描并加载BeanDefinition
  2. 实例化Bean
  3. 注入Bean依赖关系
  4. 初始化Bean
  5. 将Bean注册到容器

tcp和udp区别,tcp为什么可靠

  1. TCP 是面向连接的协议,需要三次握手连接,四次挥手断开,确保数据可以有序、可靠传输
  2. UDP是无连接的协议,减少了延迟,因此它的开销较小,适合于实时性要求高的应用。

TCP连接过程为什么要三次握手,断开链接为什么要四次挥手

TCP三次握手

  1. 客户端向服务端发送SYN包,表示请求连接
  2. 服务端接收后会回应一个SYN-ACK包,表示同意连接
  3. 客服端接收后会回应一个ACK包,表示确认连接已经建立

连接为啥要3次握手

  1. 防止出现失效的连接请求报文段被服务端接收的情况,从而产生错误。
  2. 三次握手可以确保客户端和服务端都能够正常发送和接收数据。

TCP四次挥手

  1. 主动关闭方发送FIN包,表示希望断开连接
  2. 被动关闭方收到FIN包后,会发送一个ACK包表示已经确认了对方的关闭请求
  3. 被动关闭方完成了所有的工作并准备关闭连接的时候会向对方发送FIN包
  4. 主动关闭方收到FIN包后会发送最后一个ACK包确认,然后进入到TIME-WAIT状态,状态会持续 2MSL(最大段生存期,指报文段在网络中生存的时间,超时会被抛弃) 时间,若该时间段内没有 B 的重发请求的话,就进入 CLOSED 状态。当 B 收到确认应答后,也便进入CLOSED 状态。

为啥要四次挥手

由于TCP连接是双向的,每一端都需要独立地通知另一端它已完成数据传输并希望关闭连接。

确保了连接能够在双方都准备好结束通信的情况下安全、有序地关闭。

get post区别

  1. GET:主要用于从服务器获取数据;POST:主要用于向服务器发送数据
  2. GET:通过URL查询字符串传递参数。POST:通过请求体传递参数,不显示在URL中。所以,POST可以发送更大量的数据,并且更加安全
  3. 但相比GET,POST至少不会将敏感信息暴露在URL中。
  4. GET:所有的参数都在URL中可见,POST:参数不在URL中显示,增加了隐私保护

MVC MVP MVVM区别

MVC(Model-View-Controller)、MVP(Model-View-Presenter)和MVVM(Model-View-ViewModel)是三种常见的软件架构设计模式,主要用于简化用户界面的开发,并促进代码的分离与重用。

MVC

  • Controller作为中介,接收view中用户的输入,并调用Model来进行业务逻辑处理,再将结果反馈给View
  • 视图和模型之间没有直接联系,减少了耦合度。
  • 控制器可能变得庞大复杂,尤其是在大型应用中。

MVP

  • Presenter从Controller演变而来,但它更接近于View,直接管理View的行为,负责响应View的事件并调用Model进行数据处理。
  • View和Model完全解耦,所有的交互都通过Presenter完成。
  • 测试更加容易,因为Presenter可以独立于UI进行测试。
  • 可能导致大量的接口定义,增加了代码量。

MVVM

  • ViewModel(视图模型):作为桥梁,连接Model和View。它封装了来自Model的数据,并提供了这些数据的转换形式以便于View使用。同时,它也处理View发出的命令,如按钮点击等。
  • 强调数据绑定机制,使得View和ViewModel之间的同步自动化。
  • 减少了大量胶水代码(glue code),特别是在复杂的UI更新场景下。
  • 更加适合现代前端框架,如Angular、React和Vue.js等,这些框架通常内置了强大的数据绑定支持。

值传递和引用传递

  • 值传递:传递的是实际参数的副本,函数内部的修改不会影响外部的实际参数。
  • 引用传递:传递的是实际参数的引用,函数内部的修改会影响外部的实际参数。
  • Java中的情况:虽然常说Java支持引用传递,但从技术角度讲,它实际上是传递引用的副本(值传递)。不过,由于这些副本仍然指向同一个对象,因此可以间接地修改对象的内容。

svn git区别

数组 链表区别

asynctask如何线程切换的

相关文章:

  • LeetCode 632.最小区间
  • 《HTTP权威指南》 第1-2章 HTTP和URL基础
  • ArkUI-X跨平台技术落地-华为运动健康(一)
  • python大学校园旧物捐赠系统
  • ROS2 笔记汇总(2) 通信接口
  • Android Retrofit 解析
  • 数学建模会议笔记
  • FFmpeg常见命令以及解析
  • 什么真正的云原生开发?如何区别本地开发后部署到云端?
  • vb逆向常用函数
  • 配置外设参数与时钟频率 (PCLK1, PCLK2) 的关系
  • 图书整理--LeetCode
  • Linux操作系统之进程(六):进程的控制(上)
  • 01初始uni-app+tabBar+首页
  • 第八节:Vben Admin 最新 v5.0 (vben5) 快速入门 - 用户管理(下)
  • 【redis】安装与使用
  • Unity 在Scroll View内连续截图并保存本地(把滚动列表内的内容截成一个长图)
  • 自然语言处理【NLP】—— CBOW模型
  • JavaEE->多线程1
  • Vue + Spring Boot 前后端交互实践:正确使用 `Content-Type: application/json` 及参数传递方式
  • 作风建设简报--门户网站/百度账号怎么注册
  • 峰峰信息港邯郸信息港/惠州seo推广优化
  • 比较冷门的视频网站做搬运/关键词排名优化公司成都
  • 把给公司做的设计放到自己的网站上/百度小说风云榜排行榜官网
  • 建设工程合同的概念/网络优化工程师前景如何
  • 合肥做网站排名/今日军事新闻头条