第16章 面试真题解析
面试重要程度:⭐⭐⭐⭐⭐
常见提问方式:技术深度挖掘、项目细节追问、场景设计题
预计阅读时间:45分钟
开场白
兄弟,真题解析绝对是面试准备的重中之重!我收集了近两年各大厂的面试真题,从阿里、腾讯到字节、美团,每一道题都是面试官精心设计的。这些题目不仅考察你的技术深度,更能看出你的思维方式和解决问题的能力。
今天我们就把这些高频真题彻底搞透,让你在面试中游刃有余。
🏢 16.1 阿里巴巴面试真题
技术深度类
真题1:Spring Boot自动配置原理
面试官:"Spring Boot是如何实现自动配置的?@EnableAutoConfiguration注解做了什么?"
标准答案:
// 1. @EnableAutoConfiguration注解分析 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { // ... } // 2. AutoConfigurationImportSelector核心逻辑 public class AutoConfigurationImportSelector implements DeferredImportSelector { @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } // 获取自动配置类 AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } protected AutoConfigurationEntry getAutoConfigurationEntry( AnnotationMetadata annotationMetadata) { // 1. 加载spring.factories文件中的配置类 List<String> configurations = getCandidateConfigurations( annotationMetadata, attributes); // 2. 去重 configurations = removeDuplicates(configurations); // 3. 排除不需要的配置 Set<String> exclusions = getExclusions(annotationMetadata, attributes); configurations.removeAll(exclusions); // 4. 过滤(根据条件注解) configurations = getConfigurationClassFilter().filter(configurations); return new AutoConfigurationEntry(configurations, exclusions); } } // 3. 条件注解示例 @Configuration @ConditionalOnClass(DataSource.class) // 类路径存在DataSource时生效 @ConditionalOnMissingBean(DataSource.class) // 容器中没有DataSource时生效 @EnableConfigurationProperties(DataSourceProperties.class) public class DataSourceAutoConfiguration { @Bean @ConditionalOnProperty(prefix = "spring.datasource", name = "url") public DataSource dataSource(DataSourceProperties properties) { return DataSourceBuilder.create() .url(properties.getUrl()) .username(properties.getUsername()) .password(properties.getPassword()) .build(); } }
面试加分回答:
"Spring Boot自动配置的核心原理是: 1. 启动类的@SpringBootApplication包含@EnableAutoConfiguration 2. @EnableAutoConfiguration通过@Import导入AutoConfigurationImportSelector 3. AutoConfigurationImportSelector读取META-INF/spring.factories文件 4. 根据条件注解(@ConditionalOnClass等)过滤配置类 5. 最终将符合条件的配置类注册到Spring容器 这种设计的优势是: - 约定大于配置,减少样板代码 - 条件化配置,只加载需要的组件 - 可扩展性强,第三方可以提供自己的starter 我在项目中也基于这个原理开发了自定义starter..."
真题2:MySQL索引优化实战
面试官:"有一个用户表,字段包括id、name、age、city、create_time, 现在有个查询:SELECT * FROM user WHERE age > 25 AND city = '北京' AND create_time > '2023-01-01' 如何优化这个查询?"
标准答案:
-- 1. 分析查询条件 -- age > 25 (范围查询) -- city = '北京' (等值查询) -- create_time > '2023-01-01' (范围查询) -- 2. 索引设计原则:等值查询在前,范围查询在后 -- 最优索引:(city, age, create_time) 或 (city, create_time, age) -- 创建复合索引 CREATE INDEX idx_city_age_createtime ON user(city, age, create_time); -- 3. 查询优化 -- 原查询 SELECT * FROM user WHERE age > 25 AND city = '北京' AND create_time > '2023-01-01'; -- 优化后(如果不需要所有字段) SELECT id, name, age, city FROM user WHERE city = '北京' AND age > 25 AND create_time > '2023-01-01'; -- 4. 使用EXPLAIN分析执行计划 EXPLAIN SELECT * FROM user WHERE city = '北京' AND age > 25 AND create_time > '2023-01-01'; -- 5. 进一步优化:覆盖索引 CREATE INDEX idx_city_age_createtime_covering ON user(city, age, create_time, id, name);
面试加分回答:
"这个查询优化我会从几个方面考虑: 1. 索引设计: - 根据查询条件创建复合索引(city, age, create_time) - city是等值查询,放在最前面,选择性好 - age和create_time都是范围查询,顺序可以根据数据分布调整 2. 查询重写: - 避免SELECT *,只查询需要的字段 - 考虑使用覆盖索引,避免回表查询 3. 数据分布分析: - 如果city的选择性不好,考虑调整索引顺序 - 可以收集统计信息,让优化器选择最优执行计划 4. 分区优化: - 如果数据量很大,可以考虑按create_time分区 - 这样可以减少扫描的数据量 在我之前的项目中,类似的优化让查询性能提升了10倍..."
系统设计类
真题3:设计一个秒杀系统
面试官:"双11秒杀,1000万用户抢100个商品,如何设计这个系统?"
标准答案:
// 1. 系统架构设计 /* 前端 -> CDN -> 负载均衡 -> 网关 -> 秒杀服务 -> 缓存 -> 数据库 ↓ 消息队列 ↓ 订单服务 */ // 2. 核心秒杀服务 @RestController @RequestMapping("/seckill") public class SeckillController { @Autowired private SeckillService seckillService; @Autowired private RedisTemplate<String, Object> redisTemplate; // 秒杀接口 @PostMapping("/kill/{productId}") @RateLimiter(rate = 1000) // 限流 public Result<String> seckill(@PathVariable Long productId, @RequestParam Long userId) { // 1. 参数校验 if (productId == null || userId == null) { return Result.fail("参数错误"); } // 2. 用户重复购买检查 String userKey = "seckill:user:" + productId + ":" + userId; if (redisTemplate.hasKey(userKey)) { return Result.fail("您已经参与过该商品的秒杀"); } // 3. 库存预检查 String stockKey = "seckill:stock:" + productId; Long stock = redisTemplate.opsForValue().decrement(stockKey); if (stock < 0) { // 库存不足,恢复库存 redisTemplate.opsForValue().increment(stockKey); return Result.fail("商品已售罄"); } // 4. 异步处理订单 SeckillMessage message = new SeckillMessage(productId, userId); rabbitTemplate.convertAndSend("seckill.queue", message); // 5. 设置用户参与标记 redisTemplate.opsForValue().set(userKey, "1", 3600, TimeUnit.SECONDS); return Result.success("秒杀请求提交成功,请稍后查看结果"); } } // 3. 异步订单处理 @RabbitListener(queues = "seckill.queue") @Component public class SeckillOrderProcessor { @Autowired private OrderService orderService; @Autowired private RedisTemplate<String, Object> redisTemplate; public void processSeckillOrder(SeckillMessage message) { try { // 1. 再次检查库存(防止超卖) String stockKey = "seckill:stock:" + message.getProductId(); String lockKey = "seckill:lock:" + message.getProductId(); Boolean lockAcquired = redisTemplate.opsForValue() .setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS); if (!lockAcquired) { // 获取锁失败,重新入队 rabbitTemplate.convertAndSend("seckill.queue", message); return; } try { // 2. 检查数据库真实库存 Product product = productService.getById(message.getProductId()); if (product.getStock() <= 0) { // 库存不足,恢复Redis库存 redisTemplate.opsForValue().increment(stockKey); return; } // 3. 创建订单 Order order = new Order(); order.setUserId(message.getUserId()); order.setProductId(message.getProductId()); order.setStatus(OrderStatus.UNPAID); order.setCreateTime(new Date()); // 4. 扣减库存并创建订单(事务) orderService.createSeckillOrder(order, message.getProductId()); // 5. 发送订单创建成功消息 notificationService.sendOrderSuccess(message.getUserId(), order.getId()); } finally { redisTemplate.delete(lockKey); } } catch (Exception e) { log.error("处理秒杀订单失败", e); // 恢复库存 String stockKey = "seckill:stock:" + message.getProductId(); redisTemplate.opsForValue().increment(stockKey); } } } // 4. 库存预热 @Component public class SeckillStockWarmer { @Scheduled(cron = "0 0 0 * * ?") // 每天凌晨执行 public void warmUpStock() { List<SeckillProduct> products = seckillProductService.getTodayProducts(); for (SeckillProduct product : products) { String stockKey = "seckill:stock:" + product.getId(); redisTemplate.opsForValue().set(stockKey, product.getStock()); // 设置过期时间 redisTemplate.expire(stockKey, 24, TimeUnit.HOURS); } } }
面试加分回答:
"秒杀系统的核心挑战是高并发和超卖问题,我的设计思路: 1. 前端优化: - 静态资源CDN加速 - 按钮防重复点击 - 验证码防刷 2. 接入层: - 负载均衡分散流量 - 网关层限流熔断 - IP黑白名单 3. 业务层: - Redis预扣库存,快速响应 - 异步处理订单,削峰填谷 - 分布式锁防止超卖 4. 数据层: - 读写分离 - 数据库连接池优化 - 事务最小化 5. 监控告警: - 实时监控QPS、响应时间 - 库存监控和告警 - 异常订单处理 这套方案在我们的项目中支撑了千万级并发..."
🐧 16.2 腾讯面试真题
并发编程类
真题4:线程池参数调优
面试官:"线程池的核心参数有哪些?在生产环境中如何调优?"
标准答案:
// 1. 线程池核心参数 public ThreadPoolExecutor( int corePoolSize, // 核心线程数 int maximumPoolSize, // 最大线程数 long keepAliveTime, // 线程存活时间 TimeUnit unit, // 时间单位 BlockingQueue<Runnable> workQueue, // 工作队列 ThreadFactory threadFactory, // 线程工厂 RejectedExecutionHandler handler // 拒绝策略 ) { // ... } // 2. 生产环境线程池配置 @Configuration public class ThreadPoolConfig { // CPU密集型任务线程池 @Bean("cpuTaskExecutor") public ThreadPoolExecutor cpuTaskExecutor() { int coreSize = Runtime.getRuntime().availableProcessors(); return new ThreadPoolExecutor( coreSize, // 核心线程数 = CPU核数 coreSize * 2, // 最大线程数 = CPU核数 * 2 60L, // 空闲线程存活60秒 TimeUnit.SECONDS, new LinkedBlockingQueue<>(100), // 有界队列,防止OOM new CustomThreadFactory("cpu-task-"), new ThreadPoolExecutor.CallerRunsPolicy() // 调用者执行策略 ); } // IO密集型任务线程池 @Bean("ioTaskExecutor") public ThreadPoolExecutor ioTaskExecutor() { int coreSize = Runtime.getRuntime().availableProcessors() * 2; return new ThreadPoolExecutor( coreSize, // 核心线程数 = CPU核数 * 2 coreSize * 4, // 最大线程数 = CPU核数 * 4 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(200), new CustomThreadFactory("io-task-"), new ThreadPoolExecutor.AbortPolicy() // 抛异常策略 ); } // 自定义线程工厂 public static class CustomThreadFactory implements ThreadFactory { private final AtomicInteger threadNumber = new AtomicInteger(1);
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
Java面试圣经 文章被收录于专栏
Java面试圣经,带你练透java圣经