资讯动态

Java后端面试高频考点清单:Spring、MySQL与并发编程精讲

发布时间:2026/10/15 11:31:59 来源:尧图企业网站定制
简介面向Java面试者的高频考点梳理文档围绕Spring Bean生命周期、Spring MVC执行流程、Spring Boot自动装配原理、SQL优化与MySQL索引等核心模块展开内容紧凑、要点明确适合准备校招、社招或复习框架与数据库知识的Java开发人员快速查阅。PDF共1个文件压缩包大小约396KB便于在手机、电脑和平板上随时浏览。目前已有180人学习下载。文档对每个知识点都做了分层归纳例如Bean生命周期按实例化、依赖注入、初始化、销毁四个阶段解析Spring MVC流程从请求发起到视图响应逐步说明同时补充了执行计划字段解读、索引失效场景、常见索引类型等内容并给出明确的优化建议。读者可通过这份资料快速建立面试答题框架查漏补缺重点突破Spring与SQL这两大类高频考题。1. Java 高频面试题 PDF一份能直接背进脑子里的考点清单准备 Java 后端开发面试的人多半经历过这种状态面经收藏了几十篇知识点零散地躺在笔记里真要开口回答时却组织不成话。这份《Java 高频面试题.pdf》的价值恰恰在于它把 Spring、MySQL、并发编程、集合框架、Redis 这几大块的常考题目按索引方式整理好了每条都直接给出可背诵的结论和关键词。它不是什么源码剖析也不是完整的项目实战而是一份「考点地图」适合校招冲刺、社招复习、以及想系统性查漏补缺的开发者。核心思路很朴素先把答案骨架记住再往骨架里填理解比从零啃源码要快得多。2. Spring 三件套Bean 生命周期、MVC 执行流程与自动装配的答题主线Spring 相关题目在 Java 面试里占比极高而这份 PDF 里最值钱的内容就是它把三个最容易被追问的机制拆成了可以背的步骤。常见的失败方式是概念都知道但一深问就乱。这一章我按面试官追问的顺序把三块内容的记忆锚点过一遍。2.1 Bean 生命周期实例化、初始化、销毁的顺序怎么答Bean 生命周期是 Spring 面试的必问题。PDF 给出的主线很简洁实例化实例反射或工厂方法创建→ 依赖注入属性值、对象依赖→ 初始化实现 InitializingBean 接口的 afterPropertiesSet()或配置 init-method→ 销毁实现 DisposableBean 的 destroy()或配置 destroy-method。面试时只背这条线是不够的因为面试官大概率会追问「容器到底怎么把 Bean 造出来的」。这里我一般会补一层实例化用的是反射创建对象此时对象还是半成品依赖注入发生在实例化之后通过 setter 或字段注入把依赖填进去初始化阶段才调用 InitializingBean 或自定义 init 方法。代码里最常见的是这种写法public class UserService implements InitializingBean, DisposableBean { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao userDao; } Override public void afterPropertiesSet() throws Exception { // 依赖注入完成后可以在这里做初始化校验 // 比如检查 userDao 是否为 null预热缓存等 System.out.println(UserService 初始化完成); } Override public void destroy() throws Exception { // 容器关闭时释放资源 System.out.println(UserService 销毁); } }逻辑说明afterPropertiesSet() 是 InitializingBean 接口定义的方法容器在 Bean 属性填充完成后自动调用适合做依赖完整性校验或资源初始化。destroy() 则是 DisposableBean 接口的方法容器关闭时回调用于释放连接、关闭线程池这类收尾工作。参数说明如果一个 Bean 同时配置了 init-method 和 InitializingBeanSpring 的执行顺序是先调用 afterPropertiesSet()再调用自定义的 init 方法这个顺序面试里经常被当作陷阱题。再往后如果面试官想压深度会问 BeanPostProcessor 在哪个阶段介入。PDF 里没展开但你可以记住这句话BeanPostProcessor 的 postProcessBeforeInitialization 在初始化方法调用之前执行postProcessAfterInitialization 在初始化之后执行——AOP 代理就是靠后置处理器在初始化之后生成的。答到这一层基本就能区分开「背过答案」和「真理解」的候选人了。2.2 Spring MVC八步流程的前端控制器主线Spring MVC 的执行流程PDF 给了一条完整链路客户端发 HTTP 请求 → DispatcherServlet 前端控制器接收 → HandlerMapping 把 URL 映射到处理器方法 → HandlerAdapter 调用控制器方法 → Controller 执行业务逻辑返回模型 → ViewResolver 解析视图 → 渲染 HTML → 响应客户端。这条链路里面试官最看重的是你能不能抓住 DispatcherServlet 的核心地位。整条链路除了「控制器处理请求」「视图渲染」「响应客户端」这三个环节之外其余环节都要把控制权交回给前端控制器。换句话说DispatcherServlet 是总调度其他组件都是被它调用的零件。这里有一个值得记的答法把八个步骤压缩成四段话。第一段请求进来先过前端控制器第二段前端控制器问 HandlerMapping 要「这个 URL 该交给谁处理」拿到 Handler 后让 HandlerAdapter 去调用真正的 Controller第三段Controller 返回 ModelAndView前端控制器再把视图名交给 ViewResolver解析出真正的页面第四段页面渲染完成后由前端控制器把响应写回客户端。四段话对应四个核心组件面试官再追问细节你再往八步里展开。容易翻车的点是 HandlerAdapter 的作用。很多人会跳过它直接从 HandlerMapping 跳到 Controller。实际上 HandlerAdapter 是适配器模式的典型应用它负责把不同类型的 Handler比如 RequestMapping 注解方法、HttpRequestHandler、Controller 接口实现类统一适配成可执行的调用Controller 方法的参数绑定、返回值解析也都是在这里完成的。回答流程题时把它带上会显得你对框架的抽象层次有概念。2.3 Spring Boot 自动装配从 SpringBootApplication 到条件注解Spring Boot 的自动装配原理核心就在 SpringBootApplication 这个组合注解上。PDF 拆出的三个组成注解分别是 SpringBootConfiguration、ComponentScan、EnableAutoConfiguration。前两个好理解一个标识配置类一个指定扫描包路径。真正有含金量的是 EnableAutoConfiguration。它的底层是通过 Import 注解导入 AutoConfigurationImportSelector 实现类这个类会调用 getAutoConfigurationEntry() 方法读取并筛选自动配置候选类列表。筛选时会看类路径下有没有对应的依赖 jar再结合 Conditional 系列条件注解判断要不要真正生效。为了把这个抽象过程落地我自己做自定义 starter 时会写一个这样的配置类// 文件路径META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports // com.example.demo.autoconfigure.DemoAutoConfiguration AutoConfiguration ConditionalOnClass(DemoService.class) public class DemoAutoConfiguration { Bean ConditionalOnMissingBean public DemoService demoService() { return new DemoService(); } }逻辑说明AutoConfiguration 标记这是一个自动配置类ConditionalOnClass 表示类路径下存在 DemoService 时才加载这个配置ConditionalOnMissingBean 表示容器里还没有 DemoService 实例时才创建默认 Bean。参数说明AutoConfiguration.imports 是 Spring Boot 2.7 之后的配置文件路径老版本常用 META-INF/spring.factories。面试里问到自动装配的底层原理时把这个机制讲清楚就够用了。另外面试时建议补一句自动装配解决的是「依赖存在但没显式声明 Bean」的问题而不是取代手动配置。你依然可以通过 exclude 属性排除掉不需要的自动配置类别或者靠 ConditionalOnMissingBean 让自定义 Bean 优先生效。3. MySQL 优化Explain 执行计划、索引失效与 BTree 的排查思路MySQL 这块是 Java 后端面试的另一座大山。PDF 把内容分成了执行计划、索引类型、索引失效、BTree 底层四部分这是很标准的「理论与排查结合」的组合。这一章我按实际排查 SQL 的思路来讲而不是按 PDF 的目录顺序复述。3.1 Explain 怎么看从 type、key 到 Extra 的排查顺序拿到一条慢 SQL第一步永远是加 explain 关键字看执行计划。命令格式很简单EXPLAIN SELECT u.id, u.name, o.order_no FROM t_user u LEFT JOIN t_order o ON u.id o.user_id WHERE u.status 1 AND u.create_time 2024-01-01;逻辑说明explain 不会真正执行这条 SQL它只是让 MySQL 输出优化器预估的执行方案。参数说明重点看 type、key、rows 和 Extra 这四个字段。type 是访问类型性能从好到坏大致是 system const eq_ref ref range index ALL。PDF 里提到的 system 和 const 是理想情况——根据主键或唯一索引精确匹配到一行ref 是非唯一索引等值匹配range 是索引范围扫描index 是扫描整个索引树ALL 就是全表扫描这是最需要警惕的。key 字段表示实际用到的索引为 null 就是没走索引这时候优先检查 where 条件里的列有没有建索引、有没有触发索引失效。rows 是优化器预估要扫描的行数数值越大越危险。Extra 里常见几个值得注意的值Using filesort 说明排序没走索引需要额外排序Using temporary 说明用了临时表多出现在 group by 或 union 的场景Using index 是好事说明覆盖索引直接返回结果不需要回表。我在实际排查时会按这个顺序先看 type 是否糟糕再看 key 是否为 null然后看 rows 是否过大最后看 Extra 里有没有 using filesort 或 using temporary。把这四个字段看完一条 SQL 的主要问题基本就定位了。3.2 索引失效场景与 BTree 的取舍PDF 里列的索引失效场景很全使用函数或表达式、使用 NOT 或 !、or 操作符、like 前置百分号、多个索引只有第一个有效。实际开发里还有两个高频场景容易漏。一个是隐式类型转换最常见的是 varchar 字段直接用数字去查MySQL 会在底层把字段转成数字比较导致索引失效例如-- phone 字段是 varchar 类型但用数字常量去查会触发隐式类型转换 SELECT * FROM t_user WHERE phone 13800000000;另一个是违反最左前缀原则。PDF 提到组合索引只有第一个有效准确说法应该是组合索引 (a, b, c) 中查询条件必须从 a 开始才会走索引跳过 a 直接查 b 或 c索引就用不上。这是组合索引的核心约束面试常考。BTree 这块PDF 给的计算逻辑很值得记住非叶子节点不存数据只存索引键和指针每个节点约 16KB一个 key 约 8 字节一个指针约 6 字节所以一个非叶子节点能存约 1000 条索引项第二层能索引到约 100 万条数据第三层就覆盖千万级数据。因此 InnoDB 的索引树通常只有 2 到 4 层查询从根节点到叶子节点只需要几次磁盘 I/O这是 BTree 能支撑大数据量查询的根本原因。对比一下其他索引类型PDF 还提到 Hash 索引、R-Tree 空间索引、Full-text 全文索引。Hash 索引等值查询极快但不支持范围查询R-Tree 用在地理坐标数据Full-text 用于全文检索。日常业务表里默认的 B-Tree 索引准确说是 BTree依然是最通用的选择因为它同时支持等值、范围、排序。3.3 SQL 优化落地从 select * 到 limit 1 的常见做法优化规则 PDF 写了不少但面试时你要能解释「为什么」。比如「select 时指明字段避免 select *」原因是减少回表次数和网络传输量如果查询字段正好被覆盖索引包含还能直接走 Using index 连回表都省了。再比如「分页只有一页时用 limit 1」意义在于让优化器知道只查一行找到后立即停止扫描。几个我常用的落地习惯供参考能用 inner join 就不要用 left join因为 inner join 会让优化器有更多表顺序选择空间排序字段没建索引就尽量避免排序否则会有 using filesortwhere 条件里避免 null 判断因为 null 判断通常导致索引失效like 模糊查询如果必须用前置百分号可以考虑用覆盖索引兜底或改成全文检索用 union all 代替 union因为 union 会去重自带临时表开销。这部分的答案不应该只背「in 的取值不宜过多」这种结论还要能说出「为什么」。in 值过多时优化器可能放弃索引走全表扫描或者生成大量等值比较条件导致执行计划不稳定。把它理解为「控制查询复杂度」而不是「禁止 in」才是正确的姿势。4. 并发编程线程池参数、线程状态与死锁的实战边界并发是区分候选人层次的板块。PDF 覆盖了线程池种类、核心参数、执行流程、线程状态、三大特性、死锁。这一章的重点是参数怎么设、状态怎么流转、以及死锁在你的代码里会怎么出现。4.1 线程池七个核心参数与执行流程PDF 给出了 Executors 提供的四种快捷线程池但面试官考察的重点往往是 ThreadPoolExecutor 的核心构造参数。我实际项目里基本不用 Executors因为 fixed 和 single 线程池的队列是无界的任务堆积时会撑爆内存。更常用的做法是手动构造ThreadPoolExecutor executor new ThreadPoolExecutor( 4, // corePoolSize 核心线程数 16, // maximumPoolSize 最大线程数 30L, // keepAliveTime 救急线程空闲存活时间 TimeUnit.SECONDS, // unit 时间单位 new ArrayBlockingQueue(100), // workQueue 等待队列 r - new Thread(r, biz-pool- r.hashCode()), // threadFactory new ThreadPoolExecutor.CallerRunsPolicy() // handler 拒绝策略 );逻辑说明任务提交后先判断核心线程是否满没满就创建核心线程执行满了就把任务放入 workQueue队列也满了才创建救急线程数量上限是 maximumPoolSize - corePoolSize救急线程也满且队列满触发拒绝策略。参数说明corePoolSize 是常驻线程数建议根据 CPU 密集还是 I/O 密集来估I/O 密集场景可以卡在「IO 等待时间占比」附近算maximumPoolSize 要结合系统资源上限设置别盲目扩workQueue 用有界队列比无界队列安全得多。关于拒绝策略PDF 列了四种AbortPolicy 直接抛异常是默认策略CallerRunsPolicy 让提交任务的线程自己去跑相当于变相降低提交速度DiscardOldestPolicy 丢弃队列里最早的任务DiscardPolicy 直接丢弃当前任务。实际中最推荐 CallerRunsPolicy它既能限流又不会静默丢数据缺点是需要留意调用线程被阻塞的情况。4.2 多线程三特性与 volatile、synchronized 的边界PDF 把原子性、可见性、有序性讲得很清楚原子性是操作不可分割可见性是线程修改后其他线程能读到最新值有序性是防止指令重排带来的意外结果。面试时容易被追问的是「volatile 到底能保证什么」。它能保证可见性和有序性但保证不了复合操作的原子性。经典的错误示范是用 volatile 修饰计数器private volatile int count 0; public void increase() { count; // 这不是原子操作volatile 保证不了 }逻辑说明count 实际上是「读取 → 加一 → 写回」三步两个线程同时读到旧值再写回就会丢更新。参数说明volatile 适合「一个线程写、多个线程读」的开关变量比如状态标志需要原子性的场景必须用 synchronized、Lock 或者 AtomicInteger。synchronized 可以同时保证原子性、可见性、有序性但粒度粗Lock 提供了更细的控制比如 tryLock 带超时这是避免死锁的重要手段之一。4.3 线程状态流转与优雅退出线程状态这条线PDF 列出了七种状态新建、可运行、运行中、阻塞、等待、超时等待、终止。面试最常挖的坑是「阻塞和等待的区别」。按我的理解阻塞是线程想拿到一个锁但没拿到或者进入了 synchronized 代码块在等 monitor 锁等待是因为调用了 Object.wait()、join()、LockSupport.park() 这类方法需要其他线程显式唤醒。阻塞是不需要别人唤醒的锁一释放就继续等待必须有人 notify 或 unpark。优雅退出线程在真实项目里比想象中高频。不要用 Thread.stop()那是强杀。我一般用标志位配合 interruptpublic class Worker implements Runnable { private volatile boolean running true; Override public void run() { while (running !Thread.currentThread().isInterrupted()) { // 执行任务每次循环检查一次退出条件 doWork(); } // 清理资源 release(); } public void shutdown() { running false; Thread.currentThread().interrupt(); } }逻辑说明volatile running 保证多线程间的可见性isInterrupted() 捕获外部中断请求两者都满足才继续循环。参数说明shutdown() 里先置 false 再 interrupt能同时覆盖「正在等待任务」和「正在执行任务」两种状态比单用标志位更可靠。面试里提到 join() 也可以顺带说一句它让主线程等子线程结束本质也是阻塞当前线程直到目标线程终止。5. 高频坑位排查事务失效、循环依赖与 HashMap 扩容的三个重灾区这一章集中处理这份 PDF 里最容易「背了还是会踩」的三组问题。每一组我都按「现象 → 原因 → 解决」的结构来拆这也是面试回答情景题最稳妥的框架。5.1 事务失效现象、原因与解决现象一方法标了 Transactional 却没回滚。原因异常被 try-catch 吞掉了或者抛出的是非运行时异常。Spring 默认只在 RuntimeException 和 Error 时回滚受检异常默认不回滚。解决要么让异常继续向上抛要么在注解上明确 rollbackFor Exception.class。现象二同一个类内部调用另一个 Transactional 方法事务不生效。原因Spring 事务基于 AOP 代理实现自调用走的是 this 方法不会经过代理对象事务切面根本没进来。解决把事务方法拆到另一个 Bean 里或者自注入代理更常规的做法是直接用 TransactionTemplate 做编程式事务。现象三静态方法、非 public 方法、final 方法上加 Transactional。原因代理机制对静态方法和 final 方法无能为力非 public 方法在某些代理模式上也有裸露面。解决事务方法必须是 public 且不能被 final 修饰。现象四数据表本身不支持事务比如 MyISAM 引擎。原因DML 操作根本没有事务能力。解决换 InnoDB。这四条是事务失效最高频的成因面试官喜欢从「方法内部调用」这个场景往下挖必须能脱口而出代理机制这个根因。5.2 循环依赖三级缓存能救什么救不了什么循环依赖的场景两个 Bean 相互持有对方比如 A 依赖 BB 又依赖 A。PDF 里有一个值得注意的前后矛盾之处前面写「基于构造注入循环依赖 spring 可以自动处理」后面又写「基于构造注入循环依赖 spring 无法自动处理」。以目前主流的 Spring 版本来说构造注入的循环依赖是无法被三级缓存解决的因为构造 Bean 时必须先有完整的构造参数此时 A 还没创建完B 拿不到 A 的实例。字段注入和 setter 注入可以使用三级缓存核心流程是创建 A 的早期引用放入三级缓存 - B 依赖 A 时从缓存拿到早期引用 - 完成 B - 再回来完成 A。三级缓存的职责要分清第一层 singletonObjects 存放完整单例 Bean第二层 earlySingletonObjects 存放早期暴露的半成品 Bean第三层 singletonFactories 存放能生成早期引用的 ObjectFactory。解决循环依赖有两条路一是依赖注入方式从构造注入改成字段注入或 setter 注入让三级缓存有发挥空间二是加 Lazy 延迟其中一个依赖的初始化打破实例化时的依赖闭环。面试里建议主动说出「三级缓存解决的是单例和非构造注入场景构造注入依赖必须靠 Lazy 或重构」这个边界信息量判断力是满分的关键。5.3 HashMap1.7 死循环到 1.8 红黑树的演进HashMap 的存储结构PDF 写得很明确JDK 1.7 及以前是数组加链表头插法JDK 1.8 之后是数组加链表加红黑树尾插法。1.7 的并发扩容死循环问题是经典面试题多线程同时扩容时头插法会让链表倒置形成环之后 get 操作就陷入死循环。1.8 改用尾插法解决了环的形成问题但 HashMap 依然不是线程安全的并发场景要用 ConcurrentHashMap。面试进阶版会问为什么 1.8 还要引入红黑树答案是当链表长度超过阈值 8、且数组长度大于等于 64 时链表转树把最坏查找复杂度从 O(n) 降到 O(log n)削弱 hashCode 分布不均匀时的性能衰减。但树化不是免费的红黑树节点占内存更大所以树退化回链表的阈值是 6留了缓冲区避免频繁转换。还有一个高频考点是「HashMap 的默认负载因子是 0.75为什么不是 1 也不是 0.5」。0.5 浪费空间1 的含义是数组快满才扩容但此时链表会很长哈希冲突严重。0.75 是空间和时间的折中。以及 key 可以为 null但只允许一个 null 键null 键被哈希到数组下标 0 位置。把 HashMap 的面试题串成这样「为什么」的层数越挖越深比只背结论稳得多。6. 最后的临考技巧用 60 分钟自测把 PDF 考点变成肌肉记忆拿到 PDF 之后最容易犯的错是当成小说从头读到尾读的时候觉得都会面试时张口却组织不出完整答案。我从某次翻车经历里总结出一个习惯把 PDF 的每一章转成自测题卡然后用一小时做一次「三遍输出」式自测。第一遍是复述打开一节内容遮住回答部分只对着题目用自己的话讲一遍卡住的地方就是薄弱点。第二遍是写要点把刚才能讲的内容压缩成 5 到 10 个关键词比如 Bean 生命周期就是「实例化、注入、InitializingBean、init、DisposableBean、destroy」做到看一眼关键词就能展开整段话。第三遍是追问模拟针对每个考点预设面试官可能的追问方向比如讲了事务失效就要立刻条件反射讲出「代理机制」「rollbackFor」「自调用」这几个关键点。我把 PDF 的内容映射成一个 60 分钟自测表供参考时间段自测范围自测方式0-15 分钟Spring Bean 生命周期、MVC 流程、自动装配手绘流程链口述每一步组件职责15-30 分钟MySQL 执行计划、索引失效、BTree随机写三条失效 SQL说出原因和修复30-45 分钟线程池参数、三特性、线程状态现场构造一个 ThreadPoolExecutor说明每个参数45-55 分钟事务失效、循环依赖、HashMap 演进举一个事务失效场景按现象-原因-解决回答55-60 分钟回顾薄弱点把卡壳的知识点再复述一遍这套自测方法不必等到临考前才用。我把 PDF 里每章的核心题目都抽成卡片碎片时间就拿卡片自问自答答不上的回去翻 PDF 对应段落比反复全文通读有效得多。从那以后我每次准备面试都会强制自己先跑一遍这个流程把考点变成条件反射。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑