25年10月阿里国际 Java开发 实习 一面
#JAVA##JAVA面经##JAVA内推#
看到你是双专业背景~能聊聊两个专业分别学了啥?做开发时有没有互相帮上忙的地方?
“我的双专业是计算机科学与技术 + 应用数学:
- 计算机:系统学习数据结构、操作系统、网络、软件工程,掌握全栈开发能力
- 数学:深耕离散数学、概率统计、数值分析、运筹学
交叉赋能实例:
🔹 算法优化:OJ项目中判题超时问题,用数学建模分析时间复杂度,将暴力解法(O(n²))优化为前缀和(O(n))
🔹 数据验证:二手平台订单统计模块,用概率论设计抽样校验逻辑,快速定位数据异常
🔹 逻辑严谨性:数学证明训练让我写代码时习惯‘边界条件穷举’(如分页pageNum=0/-1处理)
核心价值:数学思维是‘隐形加速器’——面对复杂问题,先抽象建模再编码,减少试错成本。”
你做的OJ(在线判题)项目挺有意思!当时为啥想做这个?
“初衷:
- 课程痛点:学校ACM训练依赖校外平台,题目管理分散、无中文题解
- 个人兴趣:想深入理解‘代码如何被评判’(编译/执行/沙箱)
团队与落地:- 3人小组(我负责后端+判题核心),历时4个月
- 真实运行:部署在校内服务器,覆盖200+学生,累计提交1.2万次
- 用户反馈:
✅ 老师用它布置算法作业(自动判分+错题统计)
✅ 学生最爱‘提交后实时显示测试点通过情况’(对比传统平台只给AC/WA)
成长:从‘能跑通’到‘能用好’,深刻理解产品需以用户痛点为中心。”
Docker部署这块:当时怎么配置的?踩过什么小坑?
“Dockerfile关键配置:
FROM openjdk:17-slim COPY target/oj-system.jar /app.jar EXPOSE 8080 ENTRYPOINT ["java", "-Xms512m", "-Xmx1g", "-jar", "/app.jar"]踩坑与解决:
⚠️ 坑1:镜像过大(1.2G→300M)
→ 改用openjdk:17-slim基础镜像 + 多阶段构建(Maven编译阶段独立)
⚠️ 坑2:时区错误(日志时间差8小时)
→ 添加:ENV TZ=Asia/Shanghai && ln -snf /usr/share/zoneinfo/$TZ /etc/localtime
⚠️ 坑3:端口映射失效
→ 检查:docker run -p 8080:8080但容器内应用监听127.0.0.1 → 改为0.0.0.0
心得:Docker不是‘打包工具’,而是‘环境契约’——每次构建后必验docker logs和curl localhost:8080/health。”
RabbitMQ用在哪儿了?消费者处理结果怎么存/反馈?
“场景:OJ系统中‘代码判题’异步化(避免用户长时间等待)
流程:
1️⃣ 用户提交代码 → 生产者发消息到judge.queue(含submissionId、代码、语言)
2️⃣ 消费者(独立判题服务):
- 拉取消息 → 沙箱执行 → 生成结果(AC/WA/TLE)
- 结果存储:
• 更新DB:UPDATE submission SET result='AC', run_time=120 WHERE id=#{submissionId}
• 写Redis:SET judge:result:{submissionId} "{...}" EX 3600(供前端轮询)- 用户反馈:
• WebSocket推送(前端建立连接后实时通知)
• 失败重试:异常时basicNack(requeue=true),超3次入死信队列告警
价值:判题峰值QPS从50提升至300,用户体验从‘卡顿等待’变为‘提交即走’。”
权限控制具体体现在哪些地方?
“基于角色+数据权限双层设计:
🔹 页面级差异:
角色 可见页面 特权功能 学生 题库、我的提交 仅查看个人提交记录 老师 题库、提交管理、题目审核 批量导出成绩、设置题目可见范围 管理员 全部 + 系统监控 用户管理、判题机状态查看 🔹 技术实现:
- 前端:路由守卫根据
user.role动态生成菜单(Vue Router)- 后端:
• 接口层:@PreAuthorize("hasRole('TEACHER')")
• 数据层:MyBatis拦截器自动拼接AND creator_id = #{currentUserId}(防越权查他人题目)
细节:老师审核题目时,前端高亮显示‘待审核’标签,提升操作效率。”
TransmittableThreadLocal 数据存在哪儿?和普通 ThreadLocal 区别?
“存储位置:
- 普通
ThreadLocal:数据存在当前线程的threadLocals Map中TransmittableThreadLocal(TTL):在threadLocals基础上,额外维护holder Map(static InheritableThreadLocal),记录所有TTL实例
核心区别:
| 维度 | ThreadLocal | TransmittableThreadLocal |
|------|---------------|---------------------------|
| 线程池场景 | 子线程无法继承父线程值 | 通过TtlRunnable/TtlCallable包装Runnable,复制父线程上下文 |
| 原理 | 依赖线程创建时的inheritable机制 | 显式复制:submit前snapshot → 执行时restore → 结束后recovery |
| 项目应用:OJ系统中,用户提交判题请求时,将userId存入TTL。判题消费者(线程池执行)通过TTL获取userId,记录‘谁提交的判题任务’,避免日志丢失上下文。
关键认知:TTL不是银弹——需手动包装任务,且注意内存泄漏(用完clear)。”
MyBatis 里 #{} 和 ${} 有啥区别?平时怎么选?
“本质差异:
#{}:预编译占位符 → 生成?,由JDBC PreparedStatement设置值 → 防SQL注入${}:字符串替换 → 直接拼接 → 高危!仅限可控场景
使用准则:
✅ 99%场景用#{}:<select id="getUser" resultType="User"> SELECT * FROM user WHERE id = #{userId} <!-- 安全 --> </select>⚠️ ${} 仅限以下情况(且必须校验!):
- 动态表名:
SELECT * FROM ${tableName}→ 前端传值需白名单校验(如if (!ALLOW_TABLES.contains(tableName)) throw)- ORDER BY:
ORDER BY ${orderByColumn}→ 用枚举限制字段(如"id","create_time")
血泪教训:曾见同学用${username}查用户,被注入' OR '1'='1导致数据泄露。从此团队规范:${}必须加注释说明校验逻辑。”
MyBatis 的一级缓存和二级缓存?项目里用过吗?
“一级缓存(SqlSession级):
- 作用域:同一次SqlSession内,相同查询(SQL+参数)直接返回缓存
- 项目:默认开启,但Spring Boot中每次请求新建SqlSession,实际失效(无需干预)
二级缓存(Mapper级):- 作用域:跨SqlSession,基于namespace(Mapper接口)
- 风险:
⚠️ 多表关联查询时易脏读(A表更新,B表缓存未失效)
⚠️ 分布式环境下各节点缓存不一致
项目决策:
❌ 主动关闭二级缓存(<cache enabled="false"/>)
✅ 用Redis替代:
• 手动缓存热点数据(如题目详情)
• 更新时同步删除缓存(@CacheEvict)
认知:MyBatis缓存是‘双刃剑’,业务复杂度高时,显式控制(Redis)比隐式缓存更可靠。”
@RequestMapping 平时怎么用的?举个项目例子
“项目实践(OJ系统题目管理):
@RestController @RequestMapping("/api/problem") // 模块级前缀 public class ProblemController { // 新增题目(仅老师) @PostMapping @PreAuthorize("hasRole('TEACHER')") public Result<Long> create(@Valid @RequestBody ProblemCreateDTO dto) { return Result.success(problemService.create(dto)); } // 按ID查题目(学生/老师均可,但学生看不到未发布题) @GetMapping("/{id}") public Result<ProblemVO> getById(@PathVariable Long id) { return Result.success(problemService.getById(id, getCurrentUser())); } // 分页查询(动态条件) @GetMapping public Result<IPage<ProblemVO>> page( @RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "10") int pageSize, ProblemQuery query) { // MyBatis-Plus自动封装 return Result.success(problemService.pageQuery(pageNum, pageSize, query)); } }设计细节:
- 路径清晰:
/api/problem体现RESTful风格- 参数校验:
@Valid+ DTO注解(如@NotBlank)- 权限前置:
@PreAuthorize在Controller层拦截,避免无效请求进Service”
Spring 事务的隔离级别?“读已提交”解决啥问题?
“四大隔离级别:
级别 脏读 不可重复读 幻读 READ_UNCOMMITTED ✅ ✅ ✅ READ_COMMITTED ❌ ✅ ✅ REPEATABLE_READ ❌ ❌ ✅(InnoDB用间隙锁解决) SERIALIZABLE ❌ ❌ ❌ READ_COMMITTED 价值:
- 解决脏读:事务A修改数据未提交,事务B读到‘中间状态’(如余额扣减中读到负数)
- 项目配置:
@Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class) public void transfer(Account from, Account to, BigDecimal amount) { // 扣款+加款(避免读到未提交的负余额) }选型逻辑:
- 金融类:
REPEATABLE_READ(InnoDB默认,防不可重复读)- 普通业务:
READ_COMMITTED(平衡性能与一致性)- 避免
SERIALIZABLE(锁表,性能灾难)”
MySQL 优化有实践过吗?慢查询从哪入手?
“五步排查法(OJ系统‘题目提交记录查询慢’案例):
1️⃣ 定位:
- 开启慢日志:
slow_query_log=1, long_query_time=1mysqldumpslow -s t /var/log/mysql/slow.log找Top SQL
2️⃣ EXPLAIN 分析:- 发现
type=ALL(全表扫描),rows=50000Extra: Using filesort(ORDER BY未走索引)
3️⃣ 优化动作:- 建联合索引:
ALTER TABLE submission ADD INDEX idx_user_time (user_id, submit_time)- 重写SQL:避免
SELECT *,只查必要字段
4️⃣ 验证:- EXPLAIN:
type=range,rows=15,Extra: Using index- 耗时:1.8s → 45ms
5️⃣ 监控:- 集成Arthas:
trace com.mapper.SubmissionMapper selectPage- Grafana看板监控慢查询趋势
心得:优化不是‘猜’,而是‘数据驱动’——每改一步必验证。”
最后~你对我们团队、实习内容,或者技术栈有啥想了解的吗? 😊
#JAVA##面经##JAVA面经##Java面经#“感谢机会!我有三个聚焦成长的问题:
1️⃣ 技术深度:团队当前在高并发判题场景(如万人同时提交)有哪些技术攻坚?实习生能否参与性能压测或优化?
2️⃣ 成长路径:是否有‘技术导师制’?比如每周代码Review、参与架构讨论的机会?
3️⃣ 业务价值:这个实习岗位最希望新人在3个月内为团队创造什么具体价值?(如独立负责一个模块迭代)
补充:我渴望的不仅是写代码,更是理解技术如何驱动业务——比如OJ系统如何通过技术提升学生算法学习效率。期待在贵司找到技术与价值的结合点!”
本专栏在精不在多,内容分为八股文、大厂真实面经,面试通过后将offer和面试题私发给我,可退还专栏的收益部分费用。欢迎大家共建专栏