面试题学习手册(定向版)
基于你的简历定向准备:4 年 Java 全栈 + 石油能源行业信息化 + Vue.js + 微前端 + K8s + AI 辅助开发
本手册每道题都标注了考察点和回答思路,并结合你简历中的真实项目亮点提供"个人化答法",让你把简历上的数字(400% / 3x / 40% / 75%)讲出故事感。
目录
- 一、Java 基础与进阶
- 二、JVM 与 Java 17 新特性
- 三、并发与多线程
- 四、Spring / Spring Boot / Spring Cloud
- 五、MyBatis 与 ORM
- 六、数据库(Oracle / MySQL)
- 七、Redis
- 八、Vue.js 与前端工程化
- 九、ECharts 与报表/可视化
- 十、微前端架构
- 十一、Docker / K8s / 运维部署
- 十二、性能优化专题
- 十三、项目场景题(结合你的简历)
- 十四、系统设计题
- 十五、AI 辅助开发与工程实践
- 十六、软实力 / 业务理解题
一、Java 基础与进阶
1. HashMap 的底层原理?Java 8 和 Java 7 有什么区别?
考察点:集合框架、数据结构、扩容机制 核心要点:
- Java 7:数组 + 链表,头插法,多线程扩容会形成环形链表导致死循环
- Java 8:数组 + 链表 + 红黑树(链表长度 > 8 且数组长度 >= 64 时转红黑树),尾插法,红黑树的引入让最坏情况从 O(n) 降到 O(log n)
- 扩容:capacity 必须是 2 的幂,负载因子默认 0.75,扩容时用
(e.hash & oldCap)判断新位置 - 为什么是 2 的幂?为了用
hash & (n-1)代替取模提升性能
2. ConcurrentHashMap 在 Java 7 和 8 中的实现差异?
- Java 7:分段锁(Segment),默认 16 段,锁粒度是段
- Java 8:CAS + synchronized 锁单个链表头节点,粒度更细,并发度更高
- 为什么放弃分段锁?段数固定后并发度不可扩展,且链表树化后锁粒度可以进一步缩小
3. String、StringBuilder、StringBuffer 区别?
- String 不可变(final char[],Java 9 后改为 byte[])
- StringBuilder 非线程安全,StringBuffer 线程安全(synchronized 方法)
- 字符串拼接推荐 StringBuilder;JDK 9 后
+号拼接编译器已优化为 invokedynamic,大部分场景无需手动优化
4. final、finally、finalize 区别?
- final:修饰类/方法/变量,不可继承/覆盖/修改
- finally:异常处理块,保证执行(除非 JVM 退出)
- finalize:Object 方法,GC 前调用,Java 9 已废弃,不要依赖
5. == 和 equals 的区别?为什么要重写 equals 必须重写 hashCode?
==比较引用(基本类型比较值)equals默认也是比较引用,重写后可比较内容- hashCode 契约:equals 相等则 hashCode 必须相等,否则在 HashMap 中会出现"同一个对象存两次"的 bug
6. 接口和抽象类的区别?Java 8 接口默认方法?
- 接口:全部是抽象方法(Java 8 前)、无状态;可多实现
- 抽象类:可以有实现,可以有状态;只能单继承
- Java 8:接口支持 default 方法和 static 方法,解决了接口演进问题(比如给 Collection 加 stream() 方法而不破坏现有实现)
7. Java 异常体系?Checked 和 Unchecked 异常?
- Throwable → Error(JVM 错误,OOM、StackOverflow) + Exception
- Exception → RuntimeException(Unchecked,运行时异常) + 其他(Checked,必须 try/catch 或 throws)
- 实际项目推荐:业务层尽量用 RuntimeException 自定义异常 + 全局异常处理器(
@RestControllerAdvice),避免到处 try/catch
8. Java 集合框架中的快速失败(fail-fast)?
- ArrayList、HashMap 等在迭代时如果集合结构被修改(modCount 变化),会抛 ConcurrentModificationException
- 原因:modCount 字段,迭代器会比对 expectedModCount
- 解决:用 Iterator.remove()、CopyOnWriteArrayList、ConcurrentHashMap
二、JVM 与 Java 17 新特性
你简历里提到 Java 8 升级到 Java 17,这是必问题,一定要准备透。
1. Java 17 相比 Java 8 有哪些重要新特性?
必答亮点(按实用度排序):
- var 关键字(10+):局部变量类型推断
- Switch 表达式 + 模式匹配(14+ 正式,17 预览模式匹配):
case Integer i -> ... - Text Blocks 文本块(15+):
"""多行字符串""",写 SQL/JSON 模板超实用 - Records(16+):
record Point(int x, int y) {},一行搞定 DTO - Sealed Classes 密封类(17):控制继承体系
- ZGC / Shenandoah GC:低延迟 GC,停顿 < 10ms
- 移除 CMS(Java 14 开始),默认 G1
- HTTP Client 标准化(11+):可以替代部分 OkHttp 场景
- 模块化(JPMS)(9):jigsaw
- JFR(Java Flight Recorder)开源:性能监控利器
你的故事(结合简历):
"我在项目中主导了 WPS 中间件从 Java 8 到 Java 17 的升级。升级后最直观的收益是 ZGC 让 GC 停顿从百毫秒级降到 10ms 以内,对文件在线编辑场景的体验提升很明显;代码层面,DTO 用 Record 替代 Lombok,Text Block 写文件操作的 SQL 模板更清晰,整体可维护性有提升。"
2. 从 Java 8 升级到 Java 17 踩过哪些坑?
- 移除的 API:
sun.misc.Unsafe部分方法、javax.xml.bind(JAXB)、javax.activation被移出 JDK,需要单独引入依赖 - 反射限制:默认不允许反射访问 JDK 内部类,需要
--add-opens参数 - Lombok 兼容:Lombok 需要升级到 1.18.22+
- 字节码框架:ASM、CGLib、Javassist 需升级
- Spring Boot 要求:Spring Boot 3.x 才真正支持 Java 17(Spring Boot 2.x 能跑但不推荐生产)
- GC 参数变化:CMS 相关参数已不支持,需改 G1 或 ZGC 参数
- 类加载器:AppClassLoader 不再继承 URLClassLoader
3. G1、ZGC、Shenandoah 的区别?
- G1(Garbage First):分 Region,可预测停顿,大堆(4G+)默认选择
- ZGC:并发的染色指针 + 读屏障,停顿 < 10ms,适合大内存(TB 级)低延迟场景
- Shenandoah:Red Hat 主导,类似 ZGC 的低停顿,基于 Brooks 指针
4. JVM 内存模型?
- 线程私有:程序计数器、虚拟机栈、本地方法栈
- 线程共享:堆(新生代 Eden + Survivor S0/S1、老年代)、方法区(Java 8 后元空间 Metaspace 替代永久代)
- 直接内存:NIO、Netty、Java 17 的 MemorySegment
5. 为什么 Java 8 废除了永久代?
- 永久代大小固定,容易 OOM(PermGen space)
- 方法区放在堆里,GC 效率低
- 元空间放在本地内存,默认无上限(可通过 MaxMetaspaceSize 限制)
6. 线上 CPU 飙高 / OOM 怎么排查?
标准四板斧:
top -Hp <pid>找到高 CPU 线程printf "%x\n" <tid>转十六进制jstack <pid> | grep <hex_tid> -A 30找到对应 Java 线程栈- OOM 用
jmap -dump:format=b,file=heap.hprof <pid>,用 MAT / VisualVM 分析
- 生产建议:启动参数
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/dump
7. 类加载过程?双亲委派?
- 加载 → 验证 → 准备 → 解析 → 初始化
- 双亲委派:子加载器先问父加载器,防止核心类被篡改
- 打破双亲委派的场景:Tomcat 的 WebAppClassLoader、SPI 机制(线程上下文类加载器)、JDBC
三、并发与多线程
1. synchronized 和 ReentrantLock 区别?
| 维度 | synchronized | ReentrantLock |
|---|---|---|
| 实现 | JVM 层(Monitor) | AQS + CAS |
| 可中断 | 不支持 | lockInterruptibly() |
| 公平锁 | 不支持 | 可设置 |
| 条件变量 | wait/notify(单一) | Condition(多个) |
| 自动释放 | 是 | 必须手动 unlock() |
2. volatile 的作用?能保证原子性吗?
- 可见性:修改后立即刷新到主内存
- 禁止指令重排:通过内存屏障
- 不保证原子性:
i++这种复合操作仍需加锁或用 AtomicInteger - 典型场景:单例双重检查锁的 instance 字段、状态标记位
3. 线程池的参数有哪些?拒绝策略?
7 大参数:corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler 执行流程:核心线程 → 队列 → 非核心线程 → 拒绝策略 4 种拒绝策略:AbortPolicy(抛异常)、CallerRunsPolicy(调用者线程执行)、DiscardPolicy(丢弃)、DiscardOldestPolicy(丢弃最老的) 面试送分题:阿里巴巴为什么禁用 Executors?
因为 newFixedThreadPool 和 newSingleThreadExecutor 用的是无界队列 LinkedBlockingQueue,可能堆积导致 OOM;newCachedThreadPool 最大线程数是 Integer.MAX_VALUE,可能创建过多线程 OOM。
4. AQS 原理?
- 抽象队列同步器,基于 CLH 队列 + volatile state 变量
- ReentrantLock、Semaphore、CountDownLatch、ReentrantReadWriteLock 都基于它
- 核心:tryAcquire / tryRelease 由子类实现,AQS 负责排队和唤醒
5. ThreadLocal 原理?内存泄漏?
- 每个 Thread 有一个 ThreadLocalMap,key 是 ThreadLocal 实例的弱引用,value 是强引用
- 内存泄漏:ThreadLocal 被回收后 key 为 null,但 value 不会,在线程池场景尤其严重
- 解决:用完必须 remove(),尤其是线程池中使用
6. Java 17 里的虚拟线程(Project Loom)?
- Java 21 正式支持,17 是预览,但值得了解
- 虚拟线程(VT)由 JVM 调度,不占用 OS 线程,可创建百万级
- 适合 IO 密集型,CPU 密集型仍用平台线程
- 对 Spring Boot 的影响:一行配置
spring.threads.virtual.enabled=true(Spring Boot 3.2+)
四、Spring / Spring Boot / Spring Cloud
1. Spring IOC 和 AOP 原理?
- IOC:控制反转,对象创建交给容器。核心是 BeanFactory 和 ApplicationContext
- AOP:面向切面,通过动态代理(JDK Proxy 接口代理 / CGLib 子类代理)织入逻辑
- Spring 默认:有接口用 JDK Proxy,无接口用 CGLib(Spring Boot 2.x+ 默认全用 CGLib)
2. Bean 的生命周期?
实例化 → 属性填充 → Aware 接口(BeanNameAware、BeanFactoryAware)→ BeanPostProcessor.before → 初始化(@PostConstruct → InitializingBean.afterPropertiesSet → init-method)→ BeanPostProcessor.after → 使用 → 销毁(@PreDestroy → DisposableBean.destroy → destroy-method)
3. Spring 循环依赖怎么解决?
- 三级缓存:singletonObjects(完整 Bean)、earlySingletonObjects(早期暴露但未填充属性)、singletonFactories(ObjectFactory,用于 AOP)
- 只能解决 setter 注入的单例循环依赖,构造器循环依赖无解
- 为什么需要三级缓存?二级就够填充属性,三级是为了延迟 AOP 代理对象的创建
4. @Transactional 失效场景?
- 同类自调用(走不到代理)→ 用
AopContext.currentProxy()或注入自身 - 方法不是 public
- 异常被 catch 吞掉
- 默认只回滚 RuntimeException,Checked Exception 需指定
rollbackFor = Exception.class - 数据库引擎不支持事务(MyISAM)
- 类没有被 Spring 管理(不是 Bean)
5. Spring Boot 自动装配原理?
- 启动类
@SpringBootApplication=@Configuration+@EnableAutoConfiguration+@ComponentScan @EnableAutoConfiguration通过@Import(AutoConfigurationImportSelector.class)加载- Spring Boot 2.7 前:读
META-INF/spring.factories - Spring Boot 2.7+:读
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports - 条件装配:
@ConditionalOnClass/@ConditionalOnMissingBean/@ConditionalOnProperty
6. Spring Boot 3.x 和 2.x 的主要区别?
- 最低 Java 17
- 基于 Jakarta EE 9(包名从
javax.*改为jakarta.*,是最大的迁移痛点) - 原生支持 GraalVM 原生镜像
- Micrometer 可观测性(Tracing、Metrics)
- Spring Cloud 对应的是 2022.0.x(Kilburn)
7. Spring Cloud 核心组件?
- 注册中心:Nacos(你简历有)/ Eureka(已停更)/ Consul
- 配置中心:Nacos / Apollo / Spring Cloud Config
- 网关:Spring Cloud Gateway(替代 Zuul)
- 熔断:Sentinel / Resilience4j(替代已停更的 Hystrix)
- 负载均衡:Spring Cloud LoadBalancer(替代 Ribbon)
- 调用:OpenFeign(你简历有)
8. Nacos 的配置热更新原理?
- 长轮询:客户端发送请求,服务端 hold 住 30 秒,配置变更立即响应
@RefreshScope注解:变更时销毁 Bean 重新创建@Value和@ConfigurationProperties的区别:后者对嵌套配置和复杂类型支持更好,无需@RefreshScope也能部分自动刷新
9. Feign 调用和 RestTemplate、HTTP 直连的区别?你简历里为什么从 Feign 改为 HTTP?
你的故事:
"我们的文件服务改造前用 Feign 调用,但遇到三个问题:
- 大文件(60M+)传输时,Feign 的默认编码器会把整个流读进内存做序列化,内存压力大;
- Feign 对
multipart/form-data和二进制流的兼容性不如直接 HTTP,出现过文件损坏;- Feign 的超时、重试策略要依赖 Ribbon/LoadBalancer 配置,排查链路较长。 所以针对文件场景改用了原生 HTTP Client(Java 11 内置),通过流式传输 + 自定义超时,稳定性显著提升。但非文件的服务间调用仍保留 Feign,因为它的声明式接口和集成度更好。"
10. @Resource 和 @Autowired 区别?
- @Autowired:Spring 提供,按类型装配,配合 @Qualifier 按名称
- @Resource:JSR-250 标准,默认按名称,其次按类型
- @Inject:JSR-330 标准,按类型
五、MyBatis 与 ORM
1. MyBatis 的工作原理?
- 配置文件(XML / 注解)→ SqlSessionFactory → SqlSession → Executor → StatementHandler → ParameterHandler / ResultSetHandler → JDBC
2. #{} 和 ${} 的区别?
#{}:预编译占位符,防 SQL 注入(PreparedStatement)${}:字符串拼接,有 SQL 注入风险${}的使用场景:表名、列名、order by 字段(这些不能预编译),但必须白名单校验
3. MyBatis 一级缓存、二级缓存?
- 一级缓存:SqlSession 级别,默认开启,查询后缓存在 PerpetualCache;执行增删改或 commit 会清空
- 二级缓存:Mapper(namespace)级别,需要
<cache/>标签开启,跨 SqlSession 共享 - 生产慎用二级缓存:多表关联、多实例场景数据一致性难保证,通常用 Redis 做缓存层更可控
4. MyBatis 分页插件 PageHelper 原理?
- ThreadLocal 存储分页参数
- 通过 MyBatis 拦截器(Interceptor)拦截 Executor.query,改写 SQL 加上 limit/rownum
- 注意:PageHelper.startPage 后必须紧跟查询,否则 ThreadLocal 污染会导致下次查询被错误分页
5. 动态 SQL 的标签?
<if> <choose> <when> <otherwise> <where> <set> <foreach> <trim> <bind>
<where>自动去除开头的 AND/OR<set>自动去除结尾的逗号<foreach>collection、item、open、close、separator
6. MyBatis 和 MyBatis-Plus 的区别?
- MP 提供了 BaseMapper,单表 CRUD 零 SQL
- 条件构造器 LambdaQueryWrapper 类型安全
- 代码生成器、逻辑删除、多租户、分页插件开箱即用
- 局限:复杂业务 SQL 还是要手写 XML
六、数据库(Oracle / MySQL)
你简历用的是 Oracle,这是很多大公司/国企/能源行业的加分项。
1. Oracle 和 MySQL 的主要区别?
| 维度 | Oracle | MySQL |
|---|---|---|
| 事务隔离默认 | READ COMMITTED | REPEATABLE READ |
| 主键自增 | Sequence + Trigger(12c 后有 Identity) | AUTO_INCREMENT |
| 分页 | ROWNUM / OFFSET FETCH(12c+) | LIMIT |
| 存储过程 | PL/SQL,功能强大 | 相对弱 |
| 大对象 | CLOB / BLOB | TEXT / BLOB |
| NULL 处理 | 空字符串视为 NULL | 空字符串不是 NULL |
| 成本 | 商业授权贵 | 开源 |
2. Oracle 的 ROWNUM 和 ROW_NUMBER() 区别?
- ROWNUM:伪列,查询结果返回时才赋值,不能直接
ROWNUM > 10,要套子查询 - ROW_NUMBER() OVER(ORDER BY ...):窗口函数,可以先排序再编号
- 12c 后推荐
OFFSET n ROWS FETCH NEXT m ROWS ONLY
3. 索引失效场景?
- 在索引列上做运算 / 函数:
WHERE YEAR(create_time) = 2024 - 隐式类型转换:字符串字段传数字
- LIKE 以
%开头 - OR 连接的条件不全是索引列
- 违反最左匹配原则(联合索引)
- NOT IN /
<>/ IS NULL 有时失效(具体看优化器) - 数据量小时优化器可能选择全表扫描
4. 如何看 SQL 执行计划?
- Oracle:
EXPLAIN PLAN FOR sql;然后SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY); - MySQL:
EXPLAIN sql;,关注 type(const > ref > range > index > ALL)、key(实际用的索引)、rows(扫描行数)、Extra(Using index 好 / Using filesort 差)
5. 索引的数据结构?为什么用 B+ 树?
- B+ 树:非叶子节点只存 key,叶子节点存 data 并链表连接
- 优势:磁盘 IO 少(树矮)、范围查询高效(叶子链表)、顺序访问友好
6. 事务的 ACID?MySQL 的隔离级别?
- A 原子性(undo log)
- C 一致性(业务层面)
- I 隔离性(锁 + MVCC)
- D 持久性(redo log)
- 隔离级别:READ UNCOMMITTED(脏读)→ READ COMMITTED(不可重复读)→ REPEATABLE READ(幻读,MySQL 默认,通过间隙锁解决)→ SERIALIZABLE
7. MVCC 原理?
- 每行隐藏字段:DB_TRX_ID(事务 ID)、DB_ROLL_PTR(回滚指针,指向 undo log)
- ReadView:当前活跃事务列表
- 根据隔离级别和 ReadView 的生成时机决定是否可见
- RC 每次查询生成 ReadView,RR 事务第一次查询生成
8. 慢 SQL 怎么优化?
标准思路:
EXPLAIN看执行计划- 加索引 / 改索引(覆盖索引、联合索引最左匹配)
- 改写 SQL:避免
SELECT *、避免大 OFFSET(用游标/最大 ID)、子查询改 JOIN、IN 大列表改临时表 - 分表分库:水平拆分(ShardingSphere)
- 读写分离
- 增加缓存层(Redis)
你的故事(接口响应 400% 提升):
"我在海外平台重构核心查询接口时,原来单个接口 2~3 秒。排查后发现:
- SQL 多表关联用了
LIKE '%xx%'全表扫描,改成联合索引 + 覆盖查询;- 同一个请求里重复查字典表 N 次,引入本地缓存(Caffeine);
- 大报表的聚合查询改用 Oracle 的物化视图 + 定时刷新;
- 前端分页从传统分页改游标分页,避免深分页 offset 扫描。 综合下来接口响应从 2~3 秒降到 500ms 以内,整体提升约 400%。"
9. Redis + DB 缓存一致性怎么保证?
- Cache Aside(最常用):读时查缓存,没有则查库回填;写时先写库再删缓存(不是更新!)
- 为什么删而不更新?避免并发写导致缓存旧值覆盖新值
- 双写不一致兜底:延时双删、binlog 订阅(Canal)异步删缓存
七、Redis
1. Redis 为什么快?
- 纯内存
- 单线程(6.0 前),避免上下文切换和锁竞争
- IO 多路复用(epoll)
- 优化的数据结构(SDS、跳表、ziplist、quicklist)
- Redis 6.0 引入多线程 IO,但命令执行仍是单线程
2. Redis 有哪些数据结构?应用场景?
- String:缓存、计数器、分布式锁
- Hash:对象缓存(一个用户一个 Hash)
- List:消息队列(LPUSH + BRPOP)、最新列表
- Set:去重、标签、共同关注
- ZSet:排行榜、延时队列(score 是执行时间)
- Bitmap:签到、活跃用户统计
- HyperLogLog:UV 统计(误差 0.81%)
- Geo:地理位置
- Stream(5.0+):消息队列
3. 缓存穿透、击穿、雪崩?
- 穿透:查不存在的数据(恶意攻击)。解决:布隆过滤器、缓存空值(短过期)
- 击穿:热点 key 过期瞬间大量请求打到 DB。解决:互斥锁、热点 key 永不过期 + 后台刷新
- 雪崩:大量 key 同时过期。解决:过期时间加随机值、多级缓存、熔断降级
4. Redis 持久化?
- RDB:快照,
bgsavefork 子进程,优点是恢复快,缺点是可能丢数据 - AOF:追加命令日志,三种策略(always / everysec / no),everysec 最常用
- 混合持久化(4.0+):RDB + AOF 增量,最佳实践
5. Redis 分布式锁怎么实现?
SET key value NX PX 30000(原子)- value 要用 UUID 等唯一标识,解锁时 Lua 脚本比对再删
- 续期:看门狗(Redisson 内置)
- Redlock 争议:Martin Kleppmann 质疑过在 GC 暂停 / 时钟漂移下的正确性,不要盲目用
6. Redis 集群模式?
- 主从复制:读写分离,异步复制
- 哨兵 Sentinel:监控 + 自动故障转移
- Cluster:16384 个槽位,数据分片,P2P 通信
八、Vue.js 与前端工程化
1. Vue 2 和 Vue 3 的主要区别?
- 响应式:Object.defineProperty → Proxy(能监听新增属性、数组索引、Map/Set)
- Composition API:setup、ref、reactive,逻辑复用更清晰
- Fragment:支持多根节点
- Teleport:把内容传送到指定 DOM(Modal 场景)
- Suspense:异步组件
- 性能:编译时静态提升、patchFlag 标记动态节点
- TypeScript 支持:重写为 TS,类型推断更好
- Tree-shaking:按需引入
2. Vue 3 的 ref 和 reactive 区别?什么时候用哪个?
ref:适合基本类型,也能包对象,通过.value访问reactive:适合对象,不能直接解构(会失去响应性),需要toRefs- 约定:基本类型用 ref,复杂对象用 reactive;或者统一用 ref(实际 ref 内部对对象也用 reactive 包装)
3. 响应式原理(Vue 3 Proxy)?
const reactive = (obj) => new Proxy(obj, {
get(target, key) {
track(target, key); // 收集依赖
return Reflect.get(target, key);
},
set(target, key, value) {
Reflect.set(target, key, value);
trigger(target, key); // 触发更新
return true;
}
});- 依赖收集结构:
WeakMap<target, Map<key, Set<effect>>> - effect 是 watchEffect / computed / 组件渲染函数
4. computed 和 watch 的区别?
computed:有缓存,依赖不变不会重新计算;必须有返回值;用于派生数据watch:无缓存,监听数据变化执行副作用;可以异步;watchEffect自动收集依赖- 性能上 computed 优先
5. v-if 和 v-show 的区别?
v-if:条件不满足不渲染(真销毁组件)v-show:display: none,始终渲染- 切换频繁用 v-show,条件几乎不变用 v-if
6. Vue 组件通信方式?
- Props / Emits(父子)
- v-model(双向绑定语法糖)
- provide / inject(跨层级)
- Pinia / Vuex(全局状态)
- Event Bus(Vue 3 要用 mitt 等第三方)
- refs(父访问子)
- $attrs(透传属性,Vue 3 增强)
7. nextTick 原理?
- Vue 的响应式更新是异步的,修改数据不会立即更新 DOM
- nextTick 把回调放入微任务队列(Promise.then)或宏任务(setTimeout 兜底)
- 保证在 DOM 更新完成后执行回调
8. keep-alive 原理?
- 本身是抽象组件(不渲染 DOM)
- 通过 LRU 缓存组件实例,在 deactivated 时缓存,activated 时复用
- 配合
<router-view>的v-slot和include/exclude使用 - 生命周期钩子:onActivated、onDeactivated
9. Webpack 和 Vite 的区别?
| 维度 | Webpack | Vite |
|---|---|---|
| 开发模式 | 先打包再启动,慢 | 基于 ESM,按需编译,秒启动 |
| HMR | 依赖打包 | 原生 ESM 精准更新 |
| 生产打包 | Webpack / Rollup | Rollup |
| 生态 | 成熟,插件多 | 新兴,但增长快 |
10. Webpack 优化手段?(你简历里有"Webpack 优化")
- 构建速度:thread-loader 多进程、cache-loader 缓存、DLL 动态链接库、include/exclude 限制 loader 范围
- 产物体积:Tree Shaking、代码分割(splitChunks)、按需引入(Element Plus 的 unplugin-vue-components)、图片压缩
- 首屏速度:路由懒加载、gzip/brotli、CDN、preload/prefetch
- 分析工具:webpack-bundle-analyzer、speed-measure-webpack-plugin
11. 前端页面性能优化(你简历"页面速度提升 3 倍"必问)
7 层优化法(从里到外):
- 代码层:函数节流防抖、大列表虚拟滚动(vue-virtual-scroller)、computed 代替 methods
- 组件层:异步组件、keep-alive、v-memo、shallowRef(大对象)、defineAsyncComponent
- 构建层:代码分割、Tree Shaking、gzip
- 资源层:图片懒加载、WebP/AVIF、字体子集化、静态资源 CDN
- 网络层:HTTP/2、接口合并、缓存策略
- 渲染层:骨架屏、SSR、预渲染
- 监控层:Performance API、LCP/FID/CLS
你的故事:
"我们的报表页面初始化要 6~8 秒。我从几个方向切入:
- 路由层做了懒加载 + 组件级 defineAsyncComponent;
- 大数据量报表用 ECharts 的 appendData 流式渲染 + 虚拟滚动表格;
- 把 Element Plus 的全量引入改成按需引入,打包体积减少 40%;
- 接口做了合并,原来首屏 8 个请求合并为 3 个,并用 Promise.all 并发;
- 启用 gzip + CDN。 最终首屏时间降到 2 秒内,整体速度提升约 3 倍。"
12. Pinia 和 Vuex 的区别?
- 无 mutations(直接改 state)
- 完整 TypeScript 支持
- 模块化默认扁平(无 namespace 嵌套)
- 更小(约 1KB)
- Vue 3 官方推荐
九、ECharts 与报表/可视化
你简历里 ECharts 是明确列出的技能,报表开发是多个项目的核心。
1. ECharts 大数据量渲染卡顿怎么办?
- 数据采样:
sampling: 'lttb'(保留趋势)、'average'、'max'、'min' - 渐进渲染:
progressive: 400, progressiveThreshold: 3000 - 流式加载:
appendData分批追加 - WebGL 渲染:ECharts GL,百万级散点也能跑
- 关闭动画:
animation: false - 合并同色系列:减少 DOM 元素
2. ECharts 怎么实现联动?
- 同一个
connectgroup 的 instance:echarts.connect(['chart1', 'chart2']) - 手动派发事件:
chart.dispatchAction({ type: 'highlight', ... }) - 监听事件:
chart.on('click', handler)
3. 多维度报表设计(针对你简历"局/厂/区/单元/单井")?
- 维度建模:层级字段统一存在 dim 表,code/name 分开,支持下钻
- 前端:层级选择器 → Tree / Cascader;图表类型根据维度数量切换(1 维柱状、2 维矩阵热力图)
- 后端:参数化 SQL,注意防 SQL 注入;预聚合 + 物化视图加速
- 缓存:层级字典缓存 Redis,查询结果用 ETag + Last-Modified
- 导出:大数据量用 EasyExcel 流式写,避免 OOM
4. 动态表头 / 动态列怎么做?
- 前端:el-table 的
v-for循环 columns 数组 - 后端:DTO 用 Map<String, Object> 或者专门的
List<Map>响应 - 字段元信息单独一个接口返回,前端根据元信息渲染
5. 大报表前端导出(Excel/CSV)方案?
- 小数据量(< 1 万行):前端 xlsx / SheetJS
- 中等数据量(1~10 万):后端生成,前端下载链接
- 大数据量(10 万+):后端异步任务 + 消息通知,生成完成后推送下载链接
- Oracle 注意:CLOB 字段导出时小心内存,流式读取
十、微前端架构
你简历里有"微前端架构"和"与太极平台集成 + 多场景免登录嵌入",必被问。
1. 为什么要用微前端?
- 大型应用拆分团队独立开发、独立部署
- 多技术栈共存(老项目 Vue 2 + 新项目 Vue 3 + React)
- 渐进式重构,不一次性改造
2. 主流方案对比?
| 方案 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| qiankun | 基于 single-spa,JS/CSS 沙箱 | 生态成熟、中文文档全 | 配置复杂、对子应用有侵入 |
| micro-app | Web Components + iframe 思路 | 接入极简 | 生态相对小 |
| Wujie | iframe + WebComponent | 预加载快、隔离彻底 | 出现晚 |
| iframe | 浏览器原生 | 完全隔离 | 通信难、体验差、SEO 不友好 |
| Module Federation | Webpack 5 原生 | 构建时共享依赖 | 部署耦合 |
3. qiankun 的 JS 沙箱怎么实现?
- 快照沙箱:记录 window 属性快照,卸载时恢复(单实例场景)
- 代理沙箱:Proxy 劫持 window,子应用的修改只影响 fakeWindow(多实例)
- Legacy 沙箱:单例下增量记录
4. CSS 隔离方案?
- shadow DOM(qiankun 严格模式,但兼容性差)
- Scoped CSS:前缀化,约定命名
- CSS Modules
- 运行时添加前缀(qiankun 实验性)
5. 主子应用通信?
- qiankun 的 initGlobalState(推荐)
- Props 传入共享方法
- 自定义事件(CustomEvent)
- 全局状态库(Redux / Pinia 注入)
6. 免登录嵌入的实现(你简历重点)?
你的故事:
"太极平台集成时我们要做免登录嵌入。方案是:
- 主应用(太极)登录后,通过约定的 URL 参数传入 token(或 iframe postMessage);
- 子应用启动时解析 token,调用 SSO 接口换本系统的 session;
- 免登录的同时做来源白名单校验(Referer + 加密签名),防止 URL 泄露被盗用;
- token 过期后子应用自动回退到主应用登录页。"
7. 微前端踩过的坑?
- 全局变量冲突(window.x)
- CSS 层叠冲突(z-index、body 样式)
- 路由冲突(子应用 history 和主应用)
- 资源加载 404(publicPath 配置错误)
- 第三方库版本冲突(建议 externals + CDN 共享)
十一、Docker / K8s / 运维部署
你简历里"独立攻克华为云 K8s 部署 + K8s 快速部署手册",是强亮点。
1. Docker 和虚拟机的区别?
- VM:基于 Hypervisor,每个 VM 有独立 OS 内核,资源占用大
- Docker:共享 Host 内核,基于 namespace(隔离)+ cgroup(限制)+ UnionFS(分层)
- 启动速度:秒级 vs 分钟级
- 镜像大小:MB 级 vs GB 级
2. Docker 镜像分层原理?
- 每条 Dockerfile 指令产生一层(read-only),容器启动时在顶部加读写层
- 共享层可以复用,节省空间和传输时间
- 优化:
- 基础镜像选 alpine / distroless
- 多阶段构建(multi-stage)
- 合并 RUN 指令
- .dockerignore 排除无用文件
3. K8s 核心概念?
- Pod:最小调度单位,一个 Pod 可包含多个容器(共享网络命名空间)
- Deployment:管理 Pod 副本,滚动更新、回滚
- Service:服务发现 + 负载均衡(ClusterIP / NodePort / LoadBalancer)
- Ingress:7 层网关,域名路由
- ConfigMap / Secret:配置和敏感信息
- PV / PVC:存储抽象
- Namespace:逻辑隔离
- StatefulSet:有状态应用(MySQL、Redis)
4. Pod 生命周期?
Pending → Running → Succeeded / Failed → (Unknown)
- initContainers:主容器前运行,常用于初始化(数据库迁移、等待依赖)
- 探针:
- startupProbe:启动探针,避免启动慢的应用被 kill
- livenessProbe:存活探针,失败会重启容器
- readinessProbe:就绪探针,失败会从 Service Endpoints 摘除
5. K8s 滚动更新策略?
RollingUpdate(默认):maxSurge(最多超出副本数)、maxUnavailable(最多不可用数)Recreate:先全停再启,有停机- 回滚:
kubectl rollout undo deployment/xxx
6. 华为云 K8s 部署的踩坑点(你简历亮点)?
你的故事:
"独立完成华为云 CCE 部署时遇到的几个坑:
- 镜像仓库鉴权:SWR 需要配置 imagePullSecret,不同命名空间要分别创建;
- 节点亲和性:工业场景要求关键应用调度到独占节点,用 nodeSelector + taints/tolerations;
- 持久化存储:OBS 对象存储 vs EVS 块存储选型,文件服务用 EVS(PVC),日志归档用 OBS;
- 网络策略:VPC 子网规划 + 安全组,跨可用区调用延迟排查;
- 监控:华为云原生的 APM + Prometheus 双栈,日志 LTS;
- 生产发布前压测,给 Deployment 配了 HPA 基于 CPU/内存自动扩缩容。 最后沉淀了一份《K8s 快速部署手册》让团队后续项目能复用。"
7. K8s 怎么做配置热更新?
- ConfigMap 挂载为文件:K8s 会自动更新(约 1~2 分钟延迟)
- ConfigMap 作为环境变量:不会自动更新,需要重建 Pod
- 应用层配合:Spring Cloud K8s 提供的 ConfigMap 监听 / Nacos 配置中心
8. 怎么定位 K8s 中应用的问题?
kubectl get pods # 看 Pod 状态
kubectl describe pod <name> # 看事件(CrashLoopBackOff 原因)
kubectl logs <pod> -c <container> # 看日志
kubectl logs <pod> --previous # 看挂掉前的日志
kubectl exec -it <pod> -- sh # 进容器调试
kubectl top pod # 看资源占用9. Nacos 在 K8s 中的部署?
- 集群模式:StatefulSet + 持久化 PVC(存配置)
- 外部 MySQL:K8s 外部依赖,数据不丢
- Headless Service:内部节点互相发现
- Ingress:暴露控制台给外部
十二、性能优化专题
你简历的两个核心数字:接口响应 400% 提升、页面速度 3 倍,这部分必须要能深入讲。
1. 完整的性能优化思路?
自顶向下四层:
- 网络:CDN、HTTP/2、压缩、DNS 预解析
- 应用:并发、异步、缓存、线程池调优
- 数据:索引、SQL 改写、读写分离、分库分表
- 架构:垂直拆分、水平扩展、消息解耦
2. 如何定位性能瓶颈?
- APM 工具:SkyWalking / Pinpoint / Arthas
- JVM:jstat、jmap、jstack、Arthas 的 trace 命令
- DB:慢查询日志、Oracle AWR 报告
- 前端:Chrome DevTools Performance、Lighthouse
3. Arthas 常用命令?
dashboard:整体概况thread -n 3:最忙的 3 个线程trace com.xx.Service method:方法调用链耗时watch com.xx.Service method returnObj:观察返回值jad com.xx.Service:反编译redefine:热更新 class
4. 接口优化实战(结合你的简历)?
分层思路:
- SQL 层:慢 SQL → EXPLAIN → 加索引 / 改写 → 从 2s → 500ms
- 代码层:串行改并发(CompletableFuture)、去除重复查询(请求级缓存)
- 缓存层:Redis / Caffeine(本地缓存)
- 异步层:非关键路径用 MQ(比如发通知、写日志)
- 架构层:读写分离、分库分表
5. 前端性能指标(Core Web Vitals)?
- LCP(Largest Contentful Paint):最大内容绘制,< 2.5s
- FID(First Input Delay):首次输入延迟,< 100ms(已被 INP 取代)
- INP(Interaction to Next Paint):交互响应,< 200ms
- CLS(Cumulative Layout Shift):累积布局偏移,< 0.1
十三、项目场景题(结合你的简历)
场景 1:动态规则引擎(数据规范化从 0 到 75%)
可能被问:
- 规则如何存储?(DB 一张表:规则 ID、适用字段、校验类型、表达式、阈值、优先级)
- 怎么实现动态加载?(启动时载入缓存 + Nacos 监听变更推送)
- 怎么做复杂表达式?(内嵌 Aviator / QLExpress / MVEL 表达式引擎)
- 性能怎么保证?(规则预编译缓存、分片并行校验、批次提交)
- 怎么支持非规范数据的渐进式入库?(先校验→标记错误类型→按规则自动修正→人工确认兜底)
- 个人表达建议:讲清楚原始数据有哪几类规范性问题(空值、类型、范围、编码等),你的规则引擎是如何分层设计的。
场景 2:WPS 中间件升级 Java 8 → 17
可能被问:
- 升级的动机?(性能?安全?生态?)
- 过程中最大的 blocker?(javax → jakarta 包名?Lombok?反射权限?)
- 测试策略?(回归测试 + 性能压测 + 灰度发布)
- 如何回滚?(镜像快照 + 数据库备份 + 流量切换)
- 大文件(60M+)兼容问题的根因?
- 回答方向:Feign 默认 HttpMessageConverter 将流读入内存 → 改用 HTTP Client 的 BodyPublishers.ofFile 流式传输 / 或分片上传
场景 3:海外决策平台(长期驻场)
可能被问:
- 长期驻场和远程开发的区别是什么?
- 如何处理客户紧急需求和开发排期冲突?
- 需求变更频繁怎么办?(需求登记 → 影响评估 → 优先级 → 版本规划;重要决策出邮件留痕)
- 端午假期 3 天攻坚讲讲?(项目节点 → 范围评估 → 任务拆解 → 每天同步 → 结果交付)
场景 4:数据湖模块设计
可能被问:
- 数据湖 vs 数据仓库?(湖存原始数据 schema-on-read,仓是结构化 schema-on-write)
- 怎么管理非结构化数据?(MinIO / OBS 对象存储 + 元数据库)
- 多格式转换(表格/图件/文档)?(LibreOffice headless、POI、pdfbox、自研格式解析 LAS 文件)
- 版本管理?(对象存储版本控制 + 元数据表记录 snapshot)
场景 5:重构核心查询接口(400% 提升)
经典追问:
- 原来为什么慢?(讲具体:表大小、索引状况、SQL 问题)
- 改了哪几个关键点?(分层讲:SQL / 代码 / 缓存 / 架构)
- 怎么证明提升了 400%?(压测工具 JMeter / wrk,P50、P95、P99 对比)
- 有没有回退方案?(接口版本 v1/v2 共存,灰度切流)
场景 6:前端渲染速度 3 倍
经典追问:
- 首屏和首次可交互哪个重要?
- 你的度量指标是什么?(FCP / LCP / TTI / Lighthouse 分数)
- 虚拟滚动如何实现?(只渲染可见区域 + 上下 buffer,监听 scroll)
- 代码分割的粒度怎么定?(路由级 + 关键组件级)
十四、系统设计题
1. 如果让你设计一个生产态势感知大屏,怎么做?(贴合你的行业)
思路:
- 数据源:多个业务系统 → ETL → 数据仓库 → 宽表
- 数据层:预聚合(分钟级/小时级)、实时流(Flink 或 SQL 定时)
- 服务层:查询 API + WebSocket 推送
- 前端:ECharts 大屏模板 + 自适应布局 + 数据联动
- 运维:HPA 扩容、缓存、降级兜底
2. 设计一个动态表单系统?
- 字段元数据:type、label、required、rules、options、visibility 条件
- 布局:row/col 栅格系统
- 前端用 JSON Schema + schema-form 渲染
- 后端:字段持久化到 JSONB / CLOB,查询时动态解析
- 需要支持:联动(A 变化影响 B 选项)、条件可见、规则校验
3. 设计一个文件预览/在线编辑系统?
- 文件上传:分片 + 秒传(hash 去重) + 断点续传
- 格式转换:LibreOffice headless → PDF / HTML;Word 用 WPS 中间件或 OnlyOffice
- 权限:预签名 URL + 短期 token
- 协同编辑:OT 算法 / CRDT(Yjs),WebSocket 同步
- 版本管理:每次保存一个版本 + 差异存储
4. 设计一个驾驶舱首页?
- 布局:可配置(拖拽 Grid)、权限化
- 数据:多源聚合 + 缓存
- 响应式:不同分辨率适配(1920 / 2560 / 4K)
- 性能:组件懒加载、ECharts 延迟渲染
- 监控:异常兜底(数据为空显示占位图)
十五、AI 辅助开发与工程实践
你简历里"LLM 辅助开发工作流,开发效率提升 40%"是加分点,但要能具体讲透。
1. 你们是怎么落地 AI 辅助开发的?
讲出流程:
- 代码生成:Cursor / Claude Code / Copilot,常用于样板代码、单测、DTO 转换、SQL 写作
- 代码审查:PR 里用 AI 做初筛(命名、空指针、边界)
- 文档生成:接口文档、注释、Changelog
- 测试用例:覆盖率低的方法让 AI 先生成用例,人工 review
2. 40% 效率提升怎么度量的?
- 把任务拆成"相似复杂度"类型(单表 CRUD、报表、接口改造)
- 对比同类任务 AI 辅助前后的工时
- 实诚一点讲:不是所有场景都有提升,业务复杂度高的场景更多是辅助思考,代码还是得自己写
3. AI 生成代码的质量怎么保障?
- Prompt 工程:给清楚约束(命名规范、异常处理、日志格式)
- Review 清单:AI 代码必须人工过一遍,尤其关注安全、边界
- 单测:要求伴随代码一起生成,覆盖率达标才合并
- 不把核心业务/安全敏感逻辑完全交给 AI
4. 有没有因为 AI 辅助踩过坑?
诚实回答:
- AI 生成的 SQL 有时性能不佳(N+1、全表扫)
- AI 可能编造不存在的 API 或依赖版本
- 老项目上下文不足时,AI 建议可能脱离实际
- 解决:给足上下文(项目规范、已有代码)、人工兜底、小步提交
十六、软实力 / 业务理解题
1. 你长期驻场客户现场,有什么感受或挑战?
亮点讲法:
- 业务 sense:直接面对一线用户,对业务理解比远程深
- 响应速度:紧急问题能即时响应,信任感建立快
- 挑战:开发环境、资源受限;生活和工作节奏需要调整
- 成长:沟通能力、推动力、独立解决问题能力
2. 遇到客户需求变更频繁怎么办?
- 建立需求池,统一登记
- 评估影响(范围、工时、风险),给出多方案
- 关键决策邮件确认
- 小步迭代,每 1~2 周发一个版本
- 对于紧急插队需求,讲清楚对原计划的影响,让客户参与排期
3. 怎么处理线上问题?
标准 SOP:
- 感知:监控告警 / 用户反馈
- 止损:降级、回滚、切流
- 定位:看日志 + 监控 + 复现
- 修复:临时 hotfix + 根因修复
- 复盘:5W 分析 + 改进项 + 防呆机制
4. 怎么和产品经理 / 业务方沟通?
- 先理解意图(为什么要做),而不是直接接需求
- 复述确认,避免理解偏差
- 提供专业建议("这个方案用 A 能做,但 B 方案长远更好")
- 不硬刚,给选项 + 成本,让对方决策
5. 为什么想离开现在的公司?
加分讲法(不要踩前公司):
- 技术栈:希望在更大规模 / 新的技术场景成长
- 行业:希望从单一行业拓展到更多业务场景
- 团队:渴望在工程文化更成熟的团队学习
- 个人:到了需要向上突破的阶段
- 不要说:加班多、钱少、领导傻
6. 你 3~5 年的规划?
- 短期(1 年):深耕技术栈 + 新业务域熟悉
- 中期(3 年):成为团队技术骨干,主导架构设计
- 长期(5 年):技术专家 / 技术管理双路线,具体看贵司方向
7. 你的缺点是什么?
模板(讲真实但可控的):
- "对于陌生技术初期会有过度求完美的倾向,会花较多时间做技术选型对比。后来我给自己定了原则:选型时间不超过任务总时长的 15%,过了就先选一个能跑的,后续再优化。"
- 不要讲:拖延、急躁、不喜欢沟通这种硬伤
8. 你最有成就感的事?
结合 WPS 改造 + 通宵攻坚:
"演示关键期我们 WPS 中间件文件保存偶现失败,客户高层在场。我当天通宵定位到是大文件传输时 Feign 缓冲区溢出,连夜改成 HTTP 流式传输并做了压测验证,第二天演示零故障。客户在复盘会上专门点名表扬,季度拿了 A 评。这件事让我体会到:真正的能力不只是写代码,而是关键时刻扛得住。"
高频"送命题"提醒
以下是经常让人翻车的题目,一定要单独再过一遍:
- 你简历里 400% 是怎么算出来的?(必须能给出前后数字和测量方法)
- 40% 效率提升的度量依据是什么?
- 微前端具体用的哪个方案?踩过什么坑?
- Java 17 升级后你用了哪些新特性?(不要只说知道,要讲具体用法)
- K8s 部署你实际改过哪些 yaml?(不要只说部署,要能讲 Deployment、Service、Ingress 具体字段)
- 重构接口时的 SQL 原始语句你还记得吗?(能手写一段说明优化前后对比最佳)
- 动态规则引擎用的什么技术?(Aviator?QLExpress?自研?)
- 你独立负责的 10+ 模块,分别是什么?(至少能说 5 个名字 + 核心逻辑)
学习路径建议(按优先级)
第 1 周 - 简历项目复盘(最重要):
- 把四个项目的"我做了什么、怎么做的、效果如何"写成 STAR 讲稿
- 每个亮点数字(400%、3x、40%、75%、20+)必须能回答"怎么来的"
- 复盘 3 个最深刻的技术难点,每个至少讲 5 分钟
第 2 周 - 技术栈深度巩固:
- Java 17 新特性 + JVM 调优
- Spring Boot 3 / Spring Cloud 2022
- Vue 3 Composition API + 微前端
第 3 周 - 系统设计与场景题:
- 每天 1~2 道系统设计
- 把常见场景(高并发、缓存一致性、分布式事务)画成流程图
第 4 周 - 模拟面试 + 复盘:
- 对着镜子自述简历,全程录音回听
- 找朋友模拟技术面、HR 面
- 针对录音中的卡壳点再强化
记住一句话:面试不是考试,是销售——把"你做过什么、能带来什么"讲清楚比背八股更重要。八股是门票,项目是武器。