作业批改系统 · Java 八股速查清单(项目代码即题库)
阅读指南
原则:代码是你写的,看一眼就能想起来。每道题 5 分钟足够。
一、Spring 核心(3 题)
1. Spring Boot 自动配置原理?(文件:main.ts / DemoApplication)
一句话:@SpringBootApplication 包含 @EnableAutoConfiguration → AutoConfigurationImportSelector 扫描 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports → 按条件注解加载配置类。
你项目里:MybatisPlusAutoConfiguration、RedisAutoConfiguration、SecurityAutoConfiguration 都是这么加载的。
追问 “条件注解有哪些?”:@ConditionalOnClass(有 Redisson 才加载)、@ConditionalOnMissingBean(用户没自定义才加载)、@ConditionalOnProperty。
2. Bean 生命周期?(文件:SecurityConfig.java)
一句话:实例化 → 属性注入 → BeanPostProcessor.postProcessBeforeInitialization() → @PostConstruct → InitializingBean.afterPropertiesSet() → @Bean 的 initMethod → BeanPostProcessor.postProcessAfterInitialization() → 容器关闭时 @PreDestroy / DisposableBean.destroy()。
你项目里:SecurityConfig.@PostConstruct 里 SecurityContextHolder.setStrategyName(...) 就是个生命周期钩子。
追问 “单例 Bean 线程安全吗?”:不安全,因为多个线程共享同一个实例。用 ThreadLocal(如 RequestContextHolder)或无状态设计来解决。
3. AOP 原理?(文件:RateLimitAspect.java)
一句话:JDK 动态代理(接口)vs CGLIB(类继承)。Spring 默认用 CGLIB。@Around 包裹目标方法,joinPoint.proceed() 才真正执行。
你项目里:RateLimitAspect 是个标准 @Around 切面。Lua 脚本校验通过 → joinPoint.proceed() 放行;失败 → 调 fallback 方法或抛异常。
追问 “多个切面的执行顺序?”:@Order 控制,值越小越外层。没有显式声明时,Spring 内部按 AspectJAutoProxyRegistrar 的规则排序。
二、Spring Security + JWT(2 题)
4. JWT 认证流程?(文件:SecurityConfig.java + JwtAuthenticationFilter.java)
1 | 用户登录 → 服务端验证密码 → 签 JWT(header.payload.signature) |
你项目里:SessionCreationPolicy.STATELESS 关掉 Session。SecurityContextHolder.MODE_INHERITABLETHREADLOCAL 让异步线程也能拿到认证上下文。
追问 “JWT 踢人下线怎么做?”:无状态模式下没法直接踢。方案:Redis 维护黑名单(logout 时加入),JwtFilter 查黑名单来拒绝。
5. CSRF 为什么关了?(文件:SecurityConfig.java)
你项目里:.csrf(csrf -> csrf.disable())
答:因为前后端分离 + JWT 无状态认证,不依赖 Cookie,CSRF 攻击的条件(攻击者利用浏览器自动带 Cookie)不存在。API 只走 Authorization header,跨站请求带不了这个头。
三、Redis(3 题)
6. 缓存穿透/击穿/雪崩?(文件:CacheThroughService.java)
| 问题 | 现象 | 你的解决方案 |
|---|---|---|
| 穿透 | 查不存在的 key,每次穿透到 DB | 没做布隆过滤器(项目里有 bloom/ 目录但未集成) |
| 击穿 | 热点 key 过期瞬间,大量请求打到 DB | ✅ CacheThroughService:分布式锁 + 双重检查 + 兜底直查 |
| 雪崩 | 大量 key 同时过期,DB 瞬间压力 | ✅ CacheTTL 随机过期时间(base ± random) |
追问 “Redisson 锁怎么防止死锁?”:tryLock(waitTime, leaseTime, TimeUnit)。leaseTime(你设了 30s)到期自动释放;底层 Watchdog 每 10s 续期。
7. Redisson 分布式锁原理?(文件:CacheThroughService.java + GradingStreamConsumer.java)
1 | RLock lock = redissonClient.getLock("lock:grading:" + submissionId); |
流程:Redisson 用 Redis Hash + Lua 脚本原子加锁。Watchdog 每 10s 续期 30s。释放时检查 isHeldByCurrentThread()(用 UUID + threadId 标识持有人),防止释放别人的锁。
和 synchronized 的区别:synchronized 只锁当前 JVM,多实例部署改了就失效。Redisson 跨 JVM 互斥。
8. Redis Stream vs Kafka?(文件:AbstractStreamConsumer.java + AsyncTaskConstants.java)
| Redis Stream | Kafka | |
|---|---|---|
| 持久化 | AOF/RDB 持久化 | 磁盘持久化,更可靠 |
| 消费模型 | 消费者组,ACK 确认 | 消费者组,offset 提交 |
| 消费速度跟不上 | 消息积压,需扩容 consumer | 天然支持分区并行 |
| 适用场景 | 轻量异步任务(批改队列) | 高吞吐日志/事件流 |
你选 Redis Stream 的理由:量不大(课堂级 150 并发),无需引入额外中间件,和缓存共用一个 Redis 降低运维复杂度。
追问 “消息可靠性”:AOF everysec 每秒刷盘 → 最多丢 1 秒消息;消费者 ACK 确认 → 只删已确认消息;Pending 认领 → 消费者崩溃可用其他 consumer 认领。
四、并发/线程(2 题)
9. Daemon 线程 vs 用户线程?(文件:AbstractStreamConsumer.java)
1 | Thread t = new Thread(r, threadName()); |
答:JVM 在所有用户线程结束后才退出,Daemon 线程不阻止 JVM 退出。消费者设 Daemon 是因为 Spring Boot 关闭时不需要等它优雅完成,应用退出即可。
10. ConcurrentHashMap vs HashMap?(文件:McpController.java)
你的 tools Map 是 LinkedHashMap:
1 | private final Map<String, ToolDefinition> tools = new LinkedHashMap<>(); |
面试官问:多线程安全吗?
答:构造函数里初始化,之后只 get() 不修改,所以线程安全。如果需要运行时动态注册工具,需改 ConcurrentHashMap。
追问 “ConcurrentHashMap 原理(Java 21)”:Java 8+ 用 CAS + synchronized 锁链表头节点。Java 21 没有本质变化,主要优化在虚拟线程的 synchronized 不 pin 住载体线程。
五、MyBatis-Plus(1 题)
11. MyBatis-Plus vs JPA vs 原生 MyBatis?(文件:pom.xml + Mapper 文件)
答:MyBatis-Plus 在原生 MyBatis 上加了内置 CRUD(BaseMapper)、条件构造器(LambdaQueryWrapper)、分页插件。和 JPA 相比:SQL 完全可控(复杂查询直接写 SQL),没有 N+1 隐式查询问题。
你项目里:StudentStatsTool.execute() 里用 LambdaQueryWrapper 做条件查询,类型安全 + 防字段名拼错。
六、设计模式(1 题)
12. 你项目里用了哪些设计模式?
| 模式 | 位置 | 代码 |
|---|---|---|
| 模板方法 | AbstractStreamConsumer |
消费循环固定模板,子类覆写钩子方法 |
| 策略 | ToolDefinition 接口 |
每个 MCP Tool 是一种策略,统一接口 |
| 单例 | 所有 @Service / @Component |
Spring 容器默认单例 |
| 代理 | RateLimitAspect |
AOP 动态代理增强 |
| 观察者 | @Scheduled + StreamMonitor |
定时检查 Stream 状态 |
七、快速复习顺序(按面试出现频率)
- 缓存三兄弟(穿透/击穿/雪崩)→ 看
CacheThroughService.java - 分布式锁 → 看
GradingStreamConsumer.java里的RLock用法 - JWT 认证流程 → 看
SecurityConfig.java+JwtAuthenticationFilter.java - AOP 原理 → 看
RateLimitAspect.java - 消息队列可靠性 → 看
AbstractStreamConsumer.java+AsyncTaskConstants.java - 设计模式 → 模板方法(AbstractStreamConsumer)+ 策略(ToolDefinition)
- Bean 生命周期 → 随便搜一个
@PostConstruct - ConcurrentHashMap → 看
McpController.java
最后
项目是你的护城河。八股忘了就忘了,看一眼代码就能捡回来——因为那是你写的。
别背,边看代码边说,自然就流畅。



