一、基础概念题

1、​Java基础
问题:ArrayList和LinkedList有什么区别?在什么场景下应优先选择LinkedList?
答案:

  • 区别

    1. 底层结构:ArrayList基于动态数组实现,支持快速随机访问;LinkedList基于双向链表实现,插入和删除效率高。

    2. 时间复杂度

      • ArrayList的get(int index)为O(1),但插入/删除(非尾部)为O(n);

      • LinkedList的get(int index)为O(n),但头尾插入/删除为O(1)。

    3. 内存占用:LinkedList每个节点需额外存储前后指针,空间开销更大。

  • 场景选择
    优先选择LinkedList的场景:

    • 频繁在列表中间或头部进行插入/删除操作;

    • 不需要频繁随机访问,且对内存不敏感。

2、多线程
问题:如何实现线程安全的List?CopyOnWriteArrayList的底层原理是什么?
答案:

  • 线程安全List的实现方式

    1. 使用Collections.synchronizedList(new ArrayList<>())包装;

    2. 使用CopyOnWriteArrayList(适用读多写少场景)。

  • CopyOnWriteArrayList原理

    1. 写时复制:每次修改(如addset)时,复制原数组生成新数组,操作完成后替换原数组。

    2. 无锁读:读操作直接访问原数组,无需加锁;

    3. 写锁:写操作通过ReentrantLock保证同步,避免并发写导致数据不一致。

3、JVM内存模型
问题:Java内存模型中,堆(Heap)和栈(Stack)的区别是什么?
答案:

  • 堆(Heap)​

    1. 所有线程共享,存放对象实例和数组;

    2. 需要垃圾回收(GC)管理内存;

    3. 可能发生内存溢出(OOM)。

  • 栈(Stack)​

    1. 线程私有,存放局部变量、方法调用和基本类型变量;

    2. 栈帧随方法调用创建/销毁,自动内存管理;

    3. 可能发生栈溢出(StackOverflowError)。

4、​数据库索引
问题:数据库索引的作用是什么?哪些情况下索引会失效?
答案:

  • 作用

    1. 加速数据检索;

    2. 唯一索引保证数据唯一性;

    3. 通过索引排序减少磁盘I/O。

  • 索引失效场景

    1. 对索引列进行运算(如WHERE age+1=20);

    2. 使用前导通配符的LIKE(如LIKE '%abc');

    3. 违反最左前缀原则(联合索引未从第一列开始查询);

    4. 类型隐式转换(如字符串列用数字查询);

    5. OR条件中非索引列参与。

5、网络协议
问题:HTTP和HTTPS的主要区别是什么?HTTPS如何保证数据传输安全?
答案:

  • 区别

    1. 安全性:HTTPS通过SSL/TLS加密传输,HTTP明文传输;

    2. 端口:HTTP默认80,HTTPS默认443;

    3. 证书:HTTPS需CA证书验证服务器身份。

  • HTTPS安全机制

    1. 非对称加密:握手阶段通过RSA等算法交换对称密钥;

    2. 对称加密:后续通信使用对称密钥加密数据;

    3. 数字证书:防止中间人攻击,验证服务器真实性。

6、设计模式
问题:什么是单例模式?如何实现线程安全的懒汉式单例?
答案:

单例模式:确保一个类仅有一个实例,并提供全局访问点。

线程安全懒汉式实现

public class Singleton {  
    private static volatile Singleton instance;  
    private Singleton() {}  
    public static Singleton getInstance() {  
        if (instance == null) {  
            synchronized (Singleton.class) {  
                if (instance == null) {  
                    instance = new Singleton();  
                }  
            }  
        }  
        return instance;  
    }  
}  

关键点:双重检查锁(Double-Check Locking)+ volatile禁止指令重排序。

7、​操作系统
问题:进程和线程的区别是什么?
答案:

  • 进程

    1. 资源分配的最小单位,独立地址空间;

    2. 进程间切换开销大,需切换内存映射;

    3. 进程间通信需IPC(如管道、共享内存)。

  • 线程

    1. CPU调度的最小单位,共享进程资源;

    2. 线程切换开销小;

    3. 需通过锁、信号量等机制保证同步。

​8、安全防护
问题:什么是SQL注入?如何防止SQL注入?
答案:

  • QL注入:攻击者通过构造恶意输入,篡改SQL语句逻辑(如' OR 1=1 --)。

  • 防御措施

    1. 预编译(PreparedStatement)​:参数化查询,避免拼接SQL;

    2. 输入过滤:对用户输入进行转义或白名单验证;

    3. 最小权限原则:数据库账号避免使用高权限角色;

    4. ORM框架:如MyBatis,自动处理参数绑定。


二、框架与工具题

1、Spring核心概念
问题:Spring框架的核心功能是什么?解释控制反转(IoC)和依赖注入(DI)的区别与联系。
答案:

  • 核心功能

    1. IoC容器:管理对象的生命周期和依赖关系;

    2. AOP(面向切面编程)​:通过代理实现日志、事务等横切关注点的解耦;

    3. 简化开发:如JDBC、事务管理等模板化封装;

    4. 集成支持:与其他框架(如Hibernate、MyBatis)无缝整合。

  • IoC与DI的区别与联系

    • IoC(控制反转)​:将对象创建和依赖管理的控制权交给容器,而非程序员硬编码。

    • DI(依赖注入)​:是实现IoC的具体方式,通过构造函数、Setter方法或接口注入依赖对象。

    • 联系:DI是IoC的实现手段,IoC是DI的设计目标。

2、Spring MVC工作流程
问题:描述Spring MVC处理HTTP请求的完整流程。
答案:

  1. DispatcherServlet接收请求:作为前端控制器,统一处理所有HTTP请求。

  2. HandlerMapping路由:根据请求URL找到对应的Controller。

  3. Controller处理请求:执行业务逻辑,返回ModelAndView(数据+视图名)。

  4. ViewResolver解析视图:将视图名转换为具体视图(如JSP、Thymeleaf)。

  5. 视图渲染:将模型数据填充到视图中,生成响应内容。

  6. 返回响应:通过DispatcherServlet返回给客户端。

  • 关键组件

    • 拦截器(Interceptor):在请求前后执行(如权限校验);

    • 数据绑定:将请求参数映射到方法参数(如@RequestParam)。

3、Spring Boot自动配置
问题:Spring Boot如何实现“约定优于配置”?举例说明自动配置的典型场景。
答案:

  • 实现原理

    1. 条件注解:如@ConditionalOnClass(当类路径存在某类时生效);

    2. spring.factories:通过META-INF/spring.factories定义自动配置类;

    3. 默认配置:基于依赖的JAR包自动启用功能(如内嵌Tomcat)。

  • 典型场景

    • 内嵌Web服务器:添加spring-boot-starter-web后自动配置Tomcat;

    • 数据源:当检测到DataSource依赖时,自动配置连接池;

    • JPA:自动配置EntityManagerFactory和事务管理器。

4、常用注解对比
问题:解释@Controller、@RestController、@Service、@Repository的作用及使用场景。
答案:

  • ​**@Controller**:

    • 作用:标记为Spring MVC控制器,处理HTTP请求;

    • 场景:返回视图(如JSP)时使用,需配合视图解析器。

  • ​**@RestController**:

    • 作用:@Controller + @ResponseBody,直接返回JSON数据;

    • 场景:开发RESTful API时使用。

  • ​**@Service**:

    • 作用:标记业务逻辑层组件;

    • 场景:封装复杂业务逻辑,如事务管理。

  • ​**@Repository**:

    • 作用:标记数据访问层组件,处理持久化异常(如将SQL异常转换为Spring统一异常);

    • 场景:DAO层实现(如JPA、MyBatis Mapper)。

5、​Spring Boot配置文件
问题:Spring Boot支持哪些类型的配置文件?如何在不同环境中切换配置?
答案:

  • 配置文件类型

    1. ​**.properties文件**:如application.properties

    2. ​**.yml/.yaml文件**:层次化配置,语法更简洁。

  • 多环境配置

    1. 按环境命名:创建application-{profile}.properties(如application-dev.properties);

    2. 激活环境

      • 命令行参数:--spring.profiles.active=prod

      • 配置文件:spring.profiles.active=dev

    3. 优先级:外部配置 > 命令行参数 > 当前JAR包内配置。


三、中级应用与设计题


1、JWT鉴权流程
问题:解释JWT的鉴权流程及如何结合Spring Security实现动态权限控制。​
答案:​

  • JWT鉴权流程

    1. 用户登录:客户端发送用户名/密码到服务端;

    2. 生成Token:服务端验证通过后,使用密钥生成JWT(包含用户信息、权限、过期时间);

    3. 返回Token:客户端存储Token(通常存于LocalStorage或Cookie);

    4. 请求携带Token:后续请求在Authorization头中携带JWT;

    5. 验证Token:服务端校验签名、过期时间,并解析用户信息;

    6. 权限校验:根据Token中的权限信息,决定是否允许访问接口。

  • 结合Spring Security实现动态权限

    1. 自定义JwtAuthenticationFilter:拦截请求,解析并验证JWT,生成Authentication对象;

    2. 实现UserDetailsService:从数据库加载用户权限(如角色、菜单权限);

    3. 动态权限配置:通过@PreAuthorize注解或SecurityConfig中的antMatchers()动态匹配权限;

    4. 权限数据源:将权限规则存储在数据库,启动时加载到SecurityMetadataSource

2、​Redis缓存雪崩
问题:Redis出现缓存雪崩如何应对?
答案:

  • 缓存雪崩场景:大量缓存同时失效,导致请求直接穿透到数据库,引发服务崩溃。

  • 解决方案

    1. 随机过期时间:为缓存设置基础过期时间 + 随机值(如30分钟 + random(0, 600)秒);

    2. 互斥锁(Mutex Lock)​:缓存失效时,使用分布式锁(如Redis的SETNX)限制只有一个线程重建缓存;

    3. 热点数据永不过期:对高频访问数据,仅更新值不删除,后台异步刷新;

    4. 双层缓存策略:一级缓存(本地缓存,如Caffeine)短时间失效,二级缓存(Redis)长周期失效;

    5. 熔断降级:通过Hystrix等组件对数据库访问限流或降级;

    6. 缓存预热:服务启动时加载高频数据到缓存。

3、​Docker Compose部署
问题:如何通过Docker Compose一键部署10个微服务?举例说明关键配置。
答案:

关键配置

version: '3.8'  
services:  
  service1:  
    image: registry/service1:latest  
    ports:  
      - "8080:8080"  
    environment:  
      - SPRING_PROFILES_ACTIVE=prod  
    networks:  
      - my-network  
    depends_on:  
      - redis  
      - mysql  
  # 其他服务(service2到service10)配置类似  
  redis:  
    image: redis:alpine  
    ports:  
      - "6379:6379"  
  mysql:  
    image: mysql:8.0  
    environment:  
      MYSQL_ROOT_PASSWORD: root  
networks:  
  my-network:  
    driver: bridge  

核心要点

  1. 服务定义:每个微服务指定镜像、端口、环境变量;

  2. 依赖管理:通过depends_on声明服务启动顺序(如先启动数据库);

  3. 共享网络:所有服务加入同一网络,通过服务名互相访问(如redis:6379);

  4. 一键启动:执行docker-compose up -d启动全部服务。​

4、单元测试覆盖率
问题:如何保证单元测试覆盖率?如何推动改进核心接口覆盖率不足?
答案:

  • 保证覆盖率的方法

    1. 工具集成:使用JaCoCo或SonarQube统计覆盖率;

    2. CI/CD约束:在流水线中设置覆盖率阈值(如≥80%),否则阻断发布;

    3. 测试分层:结合单元测试(JUnit)、集成测试(TestContainers)、契约测试(Pact);

    4. 代码审查:在PR中要求新增代码必须包含测试用例。

  • 改进核心接口覆盖率不足

    1. 用例补全:针对核心接口的分支、异常场景补充测试;

    2. Mock外部依赖:使用Mockito隔离数据库、第三方API等依赖;

    3. 重构代码:将复杂逻辑拆分为可独立测试的小单元;

    4. 团队培训:通过分享会或文档规范测试编写方法;

    5. 奖惩机制:将覆盖率指标纳入KPI考核。

5、MQ幂等性与脑裂
问题:如何实现RabbitMQ消息的幂等性?如何避免集群脑裂导致的数据不一致?
答案:

  • 消息幂等性

    1. 唯一消息ID:生产者为每条消息生成唯一ID,消费者记录已处理ID(如Redis Set);

    2. 数据库去重:业务表增加msg_id字段并设置唯一索引;

    3. 版本号控制:消息携带数据版本号,仅处理更高版本的操作;

    4. 状态机校验:业务逻辑中判断当前状态是否允许执行操作(如订单已支付则不重复处理)。

  • 避免集群脑裂

    1. 镜像队列:使用RabbitMQ镜像队列(HA Queue)同步数据到多个节点;

    2. 仲裁队列(Quorum Queue)​:基于Raft协议保证数据一致性;

    3. 节点隔离策略:配置cluster_partition_handling=pause_minority,使少数节点自动暂停;

    4. 网络心跳检测:通过高可用网络和监控工具(如Keepalived)快速发现分区;

    5. 人工干预恢复:脑裂后手动确认数据一致性,再恢复节点。


四、高级系统设计题

  1. 高并发架构设计
    问题:设计支持每秒10万次数据上报的服务端架构,如何保证数据不丢失且低延迟?
    答案:

  2. 分布式一致性
    问题:如何保证高并发下单场景下的数据一致性(如库存扣减)?
    答案:

  3. JVM调优实战
    问题:如何定位GC频繁问题?举例说明JVM参数优化过程。
    答案:

  4. 线上故障排查
    问题:线上服务突然出现大量HTTP 500错误,如何快速定位?若数据库连接池耗尽如何解决?
    答案:

  5. 微服务网关设计
    问题:设计微服务网关需考虑哪些核心功能?如何实现动态路由配置?
    答案:


五、开放与行为题

1、职业规划
问题:未来3年的职业目标是什么?若对当前技术方向不感兴趣如何调整?
答案:

  • 未来3年目标

    1. 短期(1年内)​:深入当前技术栈(如高并发、分布式系统),主导或参与核心项目,积累复杂场景的实战经验;

    2. 中期(1-2年)​:向架构师角色过渡,提升系统设计能力(如性能优化、容灾设计),主导跨团队协作;

    3. 长期(3年)​:根据兴趣选择技术深耕(如云原生、AI工程化)或转向技术管理(如团队搭建、技术规划)。

  • 调整技术方向的策略

    1. 自我评估:明确兴趣点(如数据分析、前端可视化),通过小项目验证可行性;

    2. 学习迁移:利用现有技术基础横向扩展(如Java转大数据开发学习Spark/Flink);

    3. 内部转岗:与团队沟通,争取参与目标方向的边缘项目,逐步过渡;

    4. 外部尝试:通过开源贡献、技术社区分享或副业探索新领域,降低试错成本。

2、团队协作
问题:与同事对技术方案有分歧(如是否引入Redis)如何解决?
答案:

  • 解决步骤

    1. 数据驱动:用性能压测结果(如MySQL QPS瓶颈)、业务场景(如缓存高频读低频写)佐证方案;

    2. 小规模验证:搭建POC环境对比两种方案(如Redis缓存命中率 vs 数据库直接查询);

    3. 寻求共识:邀请资深同事或架构师参与讨论,综合技术成本(如运维复杂度)、长期扩展性评估;

    4. 妥协记录:若无法达成一致,优先满足核心需求并记录分歧点,后续迭代中验证优化。

  • 关键态度

    • 避免技术“站队”,聚焦业务目标;

    • 尊重对方专业视角,避免人身攻击;

    • 接受“最优解可能不存在”,选择可落地的平衡方案。