本篇内容全部来自网络汇总
Spring的AOP什么时候失效
1.只能拦截非静态方法,如果拦截静态方法将会失效
2.final方法无法被重写, 所以也无法被AOp拦截
3.异步方法,比如@Async注解的方法,因为异步方法在运行时会创建新的线程或使用线程池,AOP拦截器无法跟踪到这些新线程中的方法调用。
4.非Spring管理的对象
5.同一个bean方法中的内部调用
Redis的一致性
Redis的数据一致性保证主要依赖于事务、乐观锁和读写分离等策略
一、事务
事务是保证数据一致性的重要手段。Redis通过MULTI、EXEC和DISCARD命令支持事务操作。事务将多个命令打包成一个原子操作,要么全部执行,要么全部不执行,从而保证了数据的一致性。

二、乐观锁
乐观锁是一种基于数据版本控制的并发控制机制。在Redis中,乐观锁通常通过使用Redis的键空间通知功能实现。当一个键的值发生变化时,Redis可以发送通知给订阅该键的客户端,从而实现数据的一致性保证。
三、读写分离
读写分离是一种常用的数据库架构设计模式,通过将读操作和写操作分散到不同的数据库服务器上,实现负载均衡和数据一致性保证。
Load class和classforname创建的类有什么不一样?
ClassForName创建的类会初始化,Load Class不会初始化
Class.forName(String className)实际上会调到 forName(String name, boolean initialize,ClassLoader loader)方法
看方法注释,我们可以了解到第二个参数的含义是class是否将被初始化,重点是第二个参数,传入了true,也就是说类会被初始化,即静态代码块会执行。
loadClass(String name)方法调用了loadClass(String name, boolean resolve),resolve为false,即为通过ClassLoader.loadClass加载的类不进行解析操作,不进行解析操作就意味着初始化也不会进行,那么其类的静态参数就不会初始化,静态代码块也不会被执行。
拦截器和过滤器的区别
- 运行位置不同:过滤器是运行在Web服务器和Servlet容器之间的组件,可以拦截所有进出该容器的请求和响应;而拦截器则是针对具体的控制器方法进行拦截处理的,只在控制器内部执行。
- 执行顺序不同:过滤器的执行顺序是由其在web.xml文件中声明的顺序决定的,按照声明的顺序依次执行;而拦截器的执行顺序是根据其在配置文件中的声明顺序决定的,也就是说拦截器可以指定先后顺序。
- 功能不同:过滤器主要用于对请求进行预处理和过滤,例如设置字符集、登录验证、日志记录等操作;而拦截器则主要用于对请求进行流程控制,例如权限验证、参数注入、异常处理等操作。
- 依赖框架不同:过滤器是基于Servlet规范实现的,不依赖任何特定的框架;而拦截器则通常是针对特定的框架或库实现的,例如Spring MVC框架中的拦截器。
Java类加载机制
加载-验证-准备-解析-初始化-使用-卸载
加载:
- 获取.class文件的二进制流
- 将类信息、静态变量、字节码、常量这些.class文件中的内容放入方法区中
- 在内存中生成一个代表这个.class文件的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
验证:确保.class文件的字节流信息符合当前虚拟机的要求
准备:为类变量分配内存并设置其初始值的阶段
解析:虚拟机将常量池内的符号引用替换为直接引用的过程
初始化:执行类构造器()方法的过程,静态方法
TCP粘包拆包问题
TCP底层不会解析具体的数据内容,它会根据缓冲区的实际情况进行包的划分(发送和接收),由此会导致上层业务的一个完整的包被拆分成多个包进行发送(“拆包”),或者多个小包被封装成一个大的数据包进行发送(“粘包”),这就是所谓的TCP的拆包和粘包问题1。如果一次请求发送的数据量比较小,没达到缓冲区大小,TCP则会将多个请求合并为同一个请求进行发送,这就形成了粘包问题。如果一次请求发送的数据量比较大,超过了缓冲区大小,TCP就会将其拆分为多次发送,这就是拆包2。TCP粘包或拆包的原因有很多,常见的原因包括要发送的数据大于TCP发送缓冲区剩余空间大小,待发送数据大于MSS(TCP报文长度 - TCP头部长度 > MSS最大报文长度)等
对于粘包和拆包问题,常见的解决方案有四种:
- 发送端将每个包都封装成固定的长度,比如100字节大小。如果不足100字节可通过补0或空等进行填充到指定长度;
- 发送端在每个包的末尾使用固定的分隔符,例如\r\n。如果发生拆包需等待多个包发送过来之后再找到其中的\r\n进行合并;例如,FTP协议;
- 将消息分为头部和消息体,头部中保存整个消息的长度,只有读取到足够长度的消息之后才算是读到了一个完整的消息;
- 通过自定义协议进行粘包和拆包的处理。
ConcurrentHashMap什么时候用CAS什么时候用synchronized
找到key哈希在table中的位置,判断是否为null
- 如果是Null则cas直接添加节点
- 如果碰撞了 需要使用synchronized(f){},放弃cas,f是table那个碰撞节点
Spring事务失效的场景
1.访问权限问题,spring要求被代理的方法必须是public
2.方法用final修饰,代理类中无法重写该方法,无法添加事务功能
3.方法内部调用
4.未被spring管理
5.表不支持事务,比如MyIsam引擎的表
Redis的key的最大长度
最大长度为512MB
当key的长度不超过1024即1kb的长度的时候,基本上对性能不造成影响,但是一旦超过1024长度,随着key长度的增加,耗时也会随之增加。
Redis默认过期时间
永不过期
explain的原理
在数据库管理系统(DBMS)中,查询优化器是负责决定如何以最高效的方式执行 SQL 查询的一个重要组件。为了提高查询性能,查询优化器会考虑多种可能的执行计划,并选择其中最优的一种。然而,理解查询优化器的决策过程和实际执行的计划并不总是直观的。这就是 EXPLAIN 命令的用武之地。
EXPLAIN 是 SQL 中用于获取查询执行计划的命令。通过 EXPLAIN,我们可以查看查询优化器为给定查询选择的具体执行计划,以及该计划中的各个步骤。这有助于我们理解查询的性能瓶颈,并采取适当的优化措施。
caffeine缓存淘汰算法
Caffeine 是一个高性能的 Java 缓存库,它提供了内存高效、快速的数据结构来实现缓存功能。Caffeine 的设计目的是为了替代 Guava 的 Cache 组件,并且提供了更多的灵活性和更好的性能。
Caffeine 支持多种缓存淘汰算法,其中最常用的包括 LRU(Least Recently Used,最近最少使用)和 LFU(Least Frequently Used,最少使用)。
@value 两种方式的区别($和#)

AOP通知类型有哪些

Java中多线性线程安全的List
读多写少: 用CopyOnWriteArrayList
写多读少: 用synchronizedList
为什么jdk动态代理只能代理实现了接口的类

Spring的两大特性
IOC和AOP依赖注入和面向切面编程
wait()和sleep的区别

并发编程的特性

Redis分布式锁的缺陷

线程池中非核心的线程完成后怎么销毁

RPC跟http的区别是什么

Java堆内存溢出的可能原因:
1.过多线程导致OOM
每一个现成的开启都要占用系统内存,当线程数量太多时,有可能导致OOM,由于线程的栈空间也是在堆外分配的,因此和直接内存非常相似。如果想让系统支持更多的线程应该使用一个较小的堆空间;
2.永久区溢出;
永久区是存放类元数据的区域,如果一个系统定义了太多的类型,会导致永久区溢出;
3.GC效率低下
GC是内存回收的关键,如果GC效率低下,系统性能会受到严重影响;如果系统堆空间太小,GC所占用的事件会较多,回收释放的内存较少。
JWT里存储什么信息

SpringMVC流程

java1.8默认的垃圾回收器是什么
Parallel Scavenge和Parallel Old


Redis指令执行的流程

垃圾收集器发现问题怎么解决
Full GC触发的条件
System.gc();
老年代空间不足;
堆中产生大对象超过阈值
线下一面没回答出来的问题:
JDK1.8的新特性

2.SpringBoot如何实现异步编程,用什么注解
@Async注解,通过Enable模块驱动注解@EnableAsync开启异步功能。使用@EnableAsync来开启异步任务支持,@EnableAsync注解可以直接放在SpringBoot启动类上,也可以单独放在其他配置类上。
- 调用带有
@Async注解的方法,它将返回一个java.util.concurrent.Future实例,表示异步计算的结果。如果方法没有返回值,则返回void。
3.docker的使用常用命令

4.java输入输出流的使用
1.现在有一个第三方jar包,包里面有个类,类里面有个私有方法,我怎么调用这个方法?
反射
2.现在我有一个Java应用,配了最大堆和最小堆,配的都是2个G,但在运行一段时间后,通过top或者任务管理器发现它的内存已经占了4个G,这可能是什么原因导致的?
可能是由于栈占用的空间较大,从JVM虚拟机中内存的分配来讲,有堆,栈,方法区等等
3. Java里设计模式有哪些?用过哪些?
单例模式,工厂模式,抽象工厂模式,建造者模式,策略模式,双亲委派模式,装饰器模式,
适配器模式
4. StringBuilder和StringBuffer的区别?什么场景用StringBuffer?
StringBuffer是可变字符串,效率较低,StringBuilder是可变字符序列,效率较高
StringBuffer是线程安全的,所有公开方法都是用synchronized修饰的;StringBuilder是线程不安全的
5. Java创建多线程的方式有哪些?用线程池有哪些好处?
实现Callable的run方法(可以用FutureTask类包装Callable接口获取返回值)
Runnable接口的run方法
继承Thread类创建线程
使用线程池(更易管理,效率更好(用线程池实现,节约开销)外,还有关键的一点:有助于避免this逃逸问题——如果我们在构造器中启动一个线程,因为另一个任务可能会在构造器结束之前开始执行,此时可能会访问到初始化了一半的对象用Executor在构造器中。)
6. MySQL的聚簇索引和非聚簇索引有什么特点?每张表都有吗?有几个?如果没有主键呢?
只有一个聚簇索引,可以有多个非聚簇索引,聚簇索引是主键对应的索引,在索引的b+树上直接通过聚簇索引可以找到对应的数据,非聚簇索引一般只保留对应列的数据,和指向聚簇索引的指针。
如果没有定义主键,InnoDB会自动添加一个不可见的、长度为6字节的row_id列,即不能被任何查询访问,也不能被内部使用。

7. 现在我有两张表,一张学生表一张成绩表,它们关系是一对一,但是有的同学没有成绩,现在希望通过一条SQL查出这些没有成绩的同学。
8. MySQL用的B+树有什么特点?(回答了几点以后又问)为什么查询稳定?
- 所有叶子节点都包含键值和指针指向实际的数据块。
- 内部节点(非叶子节点)只包含键值和指向孩子节点的指针。
- 所有的叶子节点通过一个链表链接在一起,这使得范围查询更加高效。
- 树的高度相对较低,这意味着从根节点到叶子节点的距离较短,从而减少了磁盘I/O次数。
- 每个节点可以包含多个键值对,这有助于提高磁盘空间的利用率。
- B+树在插入和删除操作中能够保持平衡,确保性能的一致性。
查询稳定:
- 高度低:由于B+树的高度较低,查询通常只需要少量的磁盘I/O操作就能完成,即使是在大规模数据集上也是如此。
- 磁盘预读机制:数据库系统通常会预读一组连续的页,这样当访问一个节点时,下一个可能需要访问的节点也被加载到了内存中,减少了后续访问的磁盘I/O。
- 平衡性:B+树保证了所有的叶子节点都在同一层次上,这保证了查找任何键值的路径长度都是相同的,因此查询性能非常稳定,不会因为数据的增删而出现显著的波动。
- 顺序访问优化:由于所有叶子节点通过链表连接,对于范围查询或者排序查询,可以直接按顺序遍历叶子节点,从而提高了这类查询的效率。
9. 堆排序的实现思路是怎么样的?
- 建立堆
- 将无序数组构建成一个最大堆(或最小堆),最大堆的性质是每个父节点的值都大于或等于其子节点的值;最小堆则相反,每个父节点的值都小于或等于其子节点的值。
- 从最后一个非叶子节点开始调整,向上直至根节点,确保每个节点都能满足堆的性质。2.交换堆顶元素和堆的最后一个元素
2.反复移除堆顶元素
- 将堆顶元素(最大值或最小值)与堆的最后一个元素交换位置。
- 由于交换后的元素可能破坏了堆的性质,因此需要重新调整这个元素所在的位置,使其满足堆的性质。
- 减少堆的大小(忽略最后一个已排序好的元素),重复上述步骤直到堆的大小为1。
10.Java垃圾回收,CMS垃圾回收器
可达性算法描述一下,GC Roots 包括以下几种:
- 虚拟机栈中的引用(方法的参数、局部变量等)
- 本地方法栈中 JNI 的引用
- 类静态变量
- 运行时常量池中的常量(String 或 Class 类型)

来自深入理解 JVM 的垃圾收集器:CMS、G1、ZGC | 二哥的Java进阶之路
11.redis如何实现分布式锁
在 Redis 中, SETNX 命令是可以帮助我们实现互斥。SETNX 即 SET if Not eXists (对应 Java 中的 setIfAbsent 方法),如果 key 不存在的话,才会设置 key 的值。如果 key 已经存在, SETNX 啥也不做。
Redlock 算法的思想是让客户端向 Redis 集群中的多个独立的 Redis 实例依次请求申请加锁,如果客户端能够和半数以上的实例成功地完成加锁操作,那么我们就认为,客户端成功地获得分布式锁,否则加锁失败。
即使部分 Redis 节点出现问题,只要保证 Redis 集群中有半数以上的 Redis 节点可用,分布式锁服务就是正常的。
12.lua脚本是用来干嘛的
Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。
13.解释下切面,如何从零开始实现一个切面
切面是面向切面编程的概念,旨在提高模块化程度,通过将那些跨越多个对象的行为(通常称为“横切关注点”)分离出来,以便将它们独立处理。比如日志管理,安全检查等等。
Spring的AOP是通过动态代理实现的,从零开始实现一个切面实际上要对需要进行切面处理的类建立动态代理,将切面切入的部分通过代理插入在实际的方法的指定位置。
14.线程间通信方式有哪些
共享内存和消息传递(锁,信号量)

Java中线程通信方式七种_java线程间通信的方式-优快云博客
15.悲观锁用的多还是乐观锁
解释下悲观锁和乐观锁的场景,优劣,乐观锁是CAS和版本号机制,悲观锁类似synchronize没有获得锁的不能操作。
16.静态变量和方法在jvm哪一块
在方法区,主要存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等。
17.线程池 核心线程数 应该怎么设计,设计为多少合适
一般来说池中总线程数是核心池线程数量两倍,只要确保当核心池有线程停止时,核心池外能有线程进入核心池即可
可以发现当线程数量小于CPU核数两倍时速度明显较慢,超过两倍后速度差不多,当核心池数量过多时,速度又会显著下降 由此可以看出,核心池线程数量大小应在CPU核数两倍以上且不宜过多。 所以说,将线程池的核心池线程数量配置为CPU核数的两倍是比较合适的。
18.JVM内存结构(追问本地方法栈干嘛的,栈里都有什么参数)
内存结构:程序计数器,虚拟机栈,本地方法栈,堆,方法区
本地方法栈主要用于支持虚拟机中使用到的Native方法,也就是那些用其他语言(如C或C++)编写,并被Java代码调用的方法。当Java代码调用了一个Native方法时,该方法的执行上下文就会进入本地方法栈中,执行完毕后再返回到Java虚拟机栈中对应的Java方法处继续执行。
栈里有局部变量表,操作数栈,动态链接,方法返回地址
19.单例模式怎么实现
利用volatile和synchronize实现单例模式。双重保护。
20.常用集合、使用场景
Map,List,Set
21.Mysql的锁和隔离级别
读未提交:能读到其他事务没有提交的对数据的修改
读已提交:不能读到其他事务对没有提交的数据的修改,但是如果事务已经提交,会导致同一个事务内两次查询的结果不同
可重复读:保证相同的读取的结果都是相同的,但是可能存在幻读(快照读不会幻读,当前读会幻读)
串行化:一个事务一个事务的执行,所以不会有并发问题
22.Redis的应用场景,数据类型,持久化和数据恢复
场景:做缓存,分布式锁,消息队列等
数据类型:string,set,zset,list,hash,特殊数据类型:hyperLogLog,Bitmap,GeoSpatial
持久化:RDB和AOF
数据恢复:利用RDB或者AOF恢复
23.GC有哪些,分别说说?Young GC 和 Full GC的区别, Young GC会导致用户线程停顿吗?
GC有young gc, old gc, full gc
young gc是在新生代里面gc, old gc是在老年代gc,full gc是在全部gc,young gc根据不同的垃圾收集有不同的做法,CMS的young gc四个步骤有两个步骤回STW,G1的young gc也会导致暂停。
24.Spring Bean单例和多例的区别?Controller是不是单例,改为多例怎么改?
单例意味着对给定的Bean,spring容器只创建一个实例,线程安全
多例:Bean作用域设置为prototype,每次从spring容器请求该bean都会创建一个新的实例。
Controller默认是单例,改为多例在配置文件中或者通过注解的方式指定其作用域为prototype。

25.Kafka的topic和分区的概念?
topic是逻辑概念,分区Partition是物理概念,一个topic可以有多个分区,分区实际的体现就是文件夹。
26.使用for循环遍历ArrayList, 在其过程中删除和添加元素有什么影响?那么想要遍历的过程中添加或删除ArrayList元素,怎么做?
可能会导致ConcurrentModificationException异常,ArrayList内部维护了一个modCount变量来跟踪结构上的修改次数。当你使用迭代器进行遍历时,迭代器同样会记录这个值。如果你在迭代期间修改了列表(通过集合本身的API方法,如add或remove),并且没有通过迭代器进行相应的操作,modCount的变化将不匹配迭代器的预期,从而抛出异常以防止数据结构处于不稳定的状态。
删除元素可以用迭代器的remove()方法,添加元素比较复杂,可以新建一个ArrayList实现。
27.Spring 如何使用注解?
@ComponentScan注解自动检测和装配特定包下的组件
@Component通用的组件注解,可以标记任何类为Spring容器管理的Bean。
@Service通常用于标记业务逻辑层的类。
@Controller用于标记处理HTTP请求的类。
@Autowired用于自动装配Bean。
@Configuration用于定义配置类,通常包含@Bean方法。
28.Docker用过吗?镜像和容器的区别?
Docker是一个非常流行的容器化平台,它允许开发者打包他们的应用及其依赖项到一个轻量级、可移植的容器中,从而使得应用可以在几乎任何环境中一致地运行。
镜像是一个只读模版,可以用于创建容器。
镜像就是没有运行的程序,容器就是运行起来的程序
常用命令:
docker version 查看版本
docker images 查看docker镜像列表
docker pull 镜像名 拉取镜像
docker ps:列出运行中的容器
docker start 容器id或name:启动已停止的容器
docker exec -it 容器id /bin/bash:进入容器
docker kill 容器id:强制停止容器
29.JDK源码设计模式
参考3
30.单例和工厂模式区别
- 单例模式是一种创建型设计模式,它保证一个类只有一个实例,并提供一个全局访问点。主要用于那些需要频繁实例化然后销毁的对象,或者创建对象需要消耗大量资源的情况,通过单例模式可以避免对系统资源的浪费。典型的应用场景包括数据库连接池、线程池等,这些通常在整个应用中只需要一个实例
- 工厂模式同样是一种创建型设计模式,但它提供了一种创建对象的最佳方式,即当创建对象的过程很复杂时,则采用工厂模式。以在不指定对象具体类型的情况下创建多个系列的对象。
31.数据库会崩溃,并发量较大时不选择数据库选择什么存储?
不选择MySQL这种存储,用内存数据库比如Redis进行存储。
32.RDB和AOF存档间隙Redis宕机丢失信息怎么办
Redis集群,AOF同步策略,RDB和AOF的组合
RDB和AOF结合使用,设置AOF的策略为sync always
33.发送指令的时候redis发生异常怎么排查
1、网络层面是否有抖动; 物理层面是否有网络丢包:ifconfig查看Drop 网卡层面,查看是否被打满,网卡打满会导致严重的超时 2、服务器负载:查看CPU和Load是否有异常 3、Redis是不是使用了Swap空间。
34. 如何确认redis是否健康
- 使用Redis自带的命令行工具redis-cli,连接到Redis服务器,并执行PING命令。如果返回PONG响应,表示Redis服务器正常运行。
- 检查Redis配置文件是否正确。
- 查看集群中每个节点的健康状态。
- 使用ps命令检查redis进程是否存在。
35.Redis如何避免数据丢失?
持久化、主从复制、高可用集群、备份和恢复
36.如何查看redis日志
如果是性能日志,使用 redis-cli 连上后执行 INFO 命令就行,查看错误日志的话,使用 tail -f日志文件路径查看,日志文件路径在启动配置文件里有设置,例如:logfile/usr/local/var/log/redis.log
37.Kafka哪些场景消息丢失
- 生产者错误:例如网络故障、错误的主题或分区选择。
- 消息堆积:当Kafka的分区或主题无法处理生产者发送的消息速度时。
- 持久化配置不正确:例如副本因子设置不正确或日志存储空间不足。
- 节点故障:如果主节点在崩溃前尚未将消息同步到副本节点,消息可能会丢失。
- 未及时同步:如果副本节点未能及时从主节点同步最新的消息数据,而主节点发生故障,尚未同步的消息可能会丢失。
- 日志清理策略配置不当:可能会导致重要的消息被误删。
38. 消费者关闭自动提交,服务宕机了,导致 消息重复消费怎么办
消费消息服务做幂等校验,比如 Redis 的 set、MySQL 的主键等天然的幂等功能。这种方法最有效。
39. 雪花算法和UUID说一下,雪花算法有什么弊端
都是生成唯一标识符的方法
UUID有多个版本,其中最常用的是基于时间戳(Version 1)和随机数(Version 4)。Version 1的UUID根据机器的MAC地址、当前时间和序列号生成,Version 4则是完全随机生成。
优点是跨平台,易于生成,几乎可以保证全平台唯一。
缺点长度较长并且无序。
雪花算法最初由Twitter开发,用于生成一个递增的64位整数作为ID。这个ID包含时间戳、机器标识码、序列号等信息。
优点:生成速度快,较短
缺点:时间戳溢出风险,严格时钟同步,否则可能导致 ID跳号
40. hashmap的 底层实现
数组+链表/红黑树
41.红黑树和avl的区别

42.java中父类和子类之间的在初始化的时候的中静态成员变量,普通成员变量和构造方法的初始化顺序。
父类静态域>子类静态域>父类成员变量初始化>父类构造块>父类构造方法>子类成员变量初始化>子类构造块>子类构造方法
拓展出继承初始化顺序:父类对象>属性初始化>构造方法>子类属性初始化>构造方法
43.java中G1垃圾回收器
分出多个Region,Region中有新生代老年代,对象大于Region大小的直接送到Humongous 区。
44.新生代和老年代的区别
新生代用于存放新创建的对象,分为Eden区和Survivor区,一个Eden两个Survivor,垃圾回收频率较高。一般用复制算法清除。
老年代用于存放生命周期较长的对象,垃圾收集频率较低,一般用标记清除算法。
年龄大于15进入老年代
45.java中的锁类型,他们之间有什么区别
synchronized:允许你在方法级别或代码块级别上同步代码。
ReentrantLock类:可中断的等待、定时锁等待、公平锁选择等高级功能,需要手动获取锁。
ReadWriteLock接口:提供了读锁和写锁两种锁,允许多个读取者同时访问共享资源,但是一次只有一个写入者可以访问。
StampedLock:乐观锁机制,它支持乐观读、写以及悲观写操作,通过版本号(stamp)来管理锁,而不是直接使用互斥锁,这样可以减少锁的竞争。
47.mysql怎么查看是否走了索引
可以用explain关键字查看SQL查询过程,查询结果中的possible_keys表示SQL查询使用到的索引,key显示SQL实际查询结果使用的索引,rows显示mysql认为它执行查询时必须检查的行数。
MySQL如何查看SQL查询是否用到了索引?_查看sql是否使用了索引-优快云博客
48.mysql索引失效有哪些场景


49.redis为什么这么快

50.AOP的应用场景
场景一: 记录日志
场景二: 监控方法运行时间 (监控性能)
场景三: 权限控制
场景四: 缓存优化 (第一次调用查询数据库,将查询结果放入内存对象, 第二次调用, 直接从内存对象返回,不需要查询数据库 )
场景五: 事务管理 (调用方法前开启事务, 调用方法后提交关闭事务 )
51.springboot的启动流程
1.首先从main找到run()方法,在执行run()方法之前new一个SpringApplication对象
2.进入run()方法,创建应用监听器SpringApplicationRunListeners开始监听
3.然后加载SpringBoot配置环境(ConfigurableEnvironment),然后把配置环境(Environment)加入监听对象中
4.然后加载应用上下文(ConfigurableApplicationContext),当做run方法的返回对象
5.最后创建Spring容器,refreshContext(context),实现starter自动化配置和bean的实例化等工作。
spring自动装配原理
Spring的注解@SpringBootApplication由三个注解组合成
@EnableAutoConfiguration:启用 SpringBoot 的自动配置机制@Configuration:允许在上下文中注册额外的 bean 或导入其他配置类@ComponentScan:扫描被@Component(@Service,@Controller)注解的 bean,注解默认会扫描启动类所在的包下所有的类 ,可以自定义不扫描某些 bean。
自动装配主要是通过@EnableAutoConfiguration注解在类路径的META-INF/spring.factories文件中找到所有的对应配置类,然后将这些自动配置类加载到spring容器中,自动配置类其实就是通过@Conditional按需加载的配置类,想要其生效必须引入spring-boot-starter-xxx包实现起步依赖
52.为什么redis和lua脚本配合使用可以保证原子性?
数据库中事务的ACID中原子性指的是“要么都成功要么都失败”,而在并发编程中的原子性指的是“操作不可拆分、不被中断“。
实际上redis用lua脚本也并不是完全的原子性,只是执行lua脚本的时候能够没有别的命令执行,一旦lua脚本中的指令执行到一半终止了,仍然无法回退。
一段 Lua 脚本可以视作一条命令执行,一段 Lua 脚本执行过程中不会有其他脚本或 Redis 命令同时执行,保证了操作不会被其他指令插入或打扰。
不过,如果 Lua 脚本运行时出错并中途结束,出错之后的命令是不会被执行的。并且,出错之前执行的命令是无法被撤销的,无法实现类似关系型数据库执行失败可以回滚的那种原子性效果。因此, 严格来说的话,通过 Lua 脚本来批量执行 Redis 命令实际也是不完全满足原子性的。
53.Java 原子类的底层是怎么保证原子性的?
原子类锁的粒度更细,具体到了变量。原子类底层利用了CAS,不会阻塞线程。
Unsafe是CAS的核心类。由于java无法直接访问底层操作系统,而是需要通过本地方法来实现。JVM还是提供了Unsafe类,他提供了硬件层面的原子操作,可以直接操作内存的数据。
如果是多CPU,CAS 底层是加了 lock 汇编指令来保障原子操作的。那么为什么我们说它是无锁呢,主要是因为它在编程语言层面上没有阻塞其他线程。
54.怎么在redis当中筛选出开头为key1:的字符串?
1.keys key1:*
KEYS命令会对整个数据库进行遍历,因此在大型数据库中使用可能会导致性能问题。
2.
使用SCAN命令
SCAN命令是一个迭代器,它能够让你逐步地遍历数据库中的键,同时提供了游标(Cursor)机制来追踪遍历的状态。使用SCAN命令更加适合在生产环境中查找匹配特定模式的键。

56.分片上传怎么优化
1.合理设置分片大小
2.并发上传
3.断点重续
4.错误重试
5.优化网络请求
6.缓存和预加载
57. tomcat如何接收http请求
Tomcat是一个Web应用服务器,同时也是一个Servlet/JSP容器。Tomcat作为Servlet容器,负责处理客户端请求,把请求传送给Servlet,并将Servlet的响应返回给客户端。
-
请求到达:
- 当一个 HTTP 请求从客户端(比如一个浏览器)发送到 Tomcat 服务器时,该请求会到达 Tomcat 中的一个名为
Connector的组件。Connector 组件负责监听特定的端口(默认情况下通常是 8080 端口),并接受来自客户端的连接请求。
- 当一个 HTTP 请求从客户端(比如一个浏览器)发送到 Tomcat 服务器时,该请求会到达 Tomcat 中的一个名为
-
请求解析:
- Connector 接收到请求之后,会解析这个请求。这包括读取请求行(包含方法类型如 GET 或 POST,请求的资源路径和协议版本),读取请求头部(包含客户端信息、请求参数等),以及可能存在的请求正文。
-
请求转发:
- 解析完成后,Connector 将请求转发给 Tomcat 的中央调度器,也就是
Container层级中的Host和Context容器。这些容器会根据请求的 URL 和主机名等信息来确定哪个 Web 应用程序应该处理这个请求。
- 解析完成后,Connector 将请求转发给 Tomcat 的中央调度器,也就是
-
请求处理:
- 一旦请求被正确地路由到了一个具体的 Web 应用程序(由 Context 容器代表),它将被进一步传递给一个或多个
Wrapper对象,每个 Wrapper 对象代表了一个具体的 Servlet。 - Servlet 负责具体业务逻辑的处理。对于 GET 或 POST 请求,Servlet 可能会分别调用
doGet()或doPost()方法来处理请求。
- 一旦请求被正确地路由到了一个具体的 Web 应用程序(由 Context 容器代表),它将被进一步传递给一个或多个
-
生成响应:
- 在请求被处理完毕后,Servlet 会构建一个 HTTP 响应,包括状态码、响应头和响应正文。这个响应会被返回给 Tomcat 的 Container 层级。
-
响应发送:
- 最后,Container 层级会把构建好的响应传递回 Connector。Connector 负责将这个响应封装成一个标准的 HTTP 响应报文,并通过 TCP/IP 协议发送回客户端。
58.301 302区别
301状态码是永久重定向(Moved Permanently),表示所请求的资源已经永久地转移到新的位置,这包含域名的改变或者是资源路径的改变。
302状态码是临时重定向(Move Temporarily),表示所请求的资源临时地转移到新的位置,一般是24到48小时以内的转移会用到302。
59.幂等性是什么
幂等性(Idempotence)是指一个操作可以被多次执行,并且无论执行多少次,结果都是相同的。
- 在HTTP协议中,幂等性是一个很重要的概念。根据HTTP规范,某些方法(如GET、HEAD、PUT和DELETE)被认为是幂等的。这意味着如果客户端多次发送同一个请求,服务器应该返回相同的结果。例如,删除一个资源的DELETE请求,无论发送多少次,最终结果都是该资源被删除一次。
60.TCP的time_wait,close_wait是什么
TIME_WAIT 是TCP连接关闭后的一种状态。当主动关闭连接的一方(通常是客户端)发送了FIN包并收到了对方的ACK确认之后,它还需要等待一段时间才能完全关闭连接。这段时间是为了确保最后一个ACK包能够顺利送达对方,如果对方没有收到这个ACK,则可以在这段时间内重传。
CLOSE_WAIT 是TCP连接关闭过程中的另一种状态。当被动关闭连接的一方(通常是服务器)收到对方发送的FIN包后,它会进入CLOSE_WAIT状态。这意味着服务器已经收到了对方的结束连接请求,但它还没有关闭自己的发送方向。
61.Java内存泄漏怎么排查
常见的内存泄漏情况:
1.静态集合,如果向静态集合中添加对象并且不再需要这些对象,它们将永远不会被垃圾回收
2.匿名内部类通常会隐式地持有对外部类的引用,这可能导致外部类的对象无法被垃圾回收。
3.监听器注册,注册的事件监听器如果没有正确注销,会持续接收事件,导致相关对象无法被垃圾回收。
4.线程泄露:如果启动的线程未正确关闭或管理,它们将继续运行,即使应用程序退出。
- 内存分析器: 使用Java内存分析器工具,如MAT(Eclipse Memory Analyzer Tool)或VisualVM,来检查堆内存中的对象和引用关系。这些工具可以帮助您找到潜在的内存泄漏。
- 日志记录: 在应用程序中添加详细的日志记录,以便跟踪对象的创建和销毁。分析日志可以帮助您了解对象的生命周期。
- 性能监控工具: 使用性能监控工具来观察内存占用、垃圾回收频率和应用程序性能。这些工具可以帮助您及早发现内存泄漏问题。
62.hashmap的put流程

63.1TB的文件,如何快速从中找到想要的数据

64.如何自定义线程池
65.HTTP1.0,1.1,2.0,3.0的区别
HTTP1.0是短连接,1.1是长连接,1.1中加入了大量的状态码,进行了带宽的优化
HTTP2.0的解析是基于二进制格式,HTTP1.x的解析是基于文本的
多路复用,共享连接,一个连接上可以用多个request,每个request对应一个id用于区分
header压缩
服务端可以主动向客户端发送消息
HTTP3.0使用UDP协议
66.Java实现HTTP跨域请求
CORS:设置了"Access-Control-Allow-Origin"头为"*",允许所有的域进行跨域请求。
代理服务器: 在服务端设置一个代理服务器,将跨域请求转发至目标地址,并将响应返回给前端页面。
835

被折叠的 条评论
为什么被折叠?



