26年2月北京独创时代 Java开发工程师 二面

1. Spring Boot Actuator中/health端点如何自定义数据库健康检查逻辑?

思路

核心讲“实现HealthIndicator接口+配置”,区分“扩展默认检查”和“自定义全量检查”两种场景,结合代码示例说明。

回答示例

Spring Boot Actuator的/health端点默认提供基础数据库健康检查(如连接是否可用),自定义数据库健康检查需实现HealthIndicator接口,步骤如下:

1. 基础配置(开启健康检查)
management:
  endpoints:
    web:
      exposure:
        include: health # 暴露health端点
  endpoint:
    health:
      show-details: always # 显示详细健康信息(生产建议when_authorized)
2. 自定义数据库健康检查(示例:检查核心表是否可访问)
@Component
public class CustomDbHealthIndicator implements HealthIndicator {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public Health health() {
        try {
            // 自定义检查逻辑:查询核心表(如user)是否可访问
            jdbcTemplate.queryForObject("SELECT 1 FROM user LIMIT 1", Integer.class);
            
            // 可选:添加自定义健康详情
            return Health.up()
                    .withDetail("db_status", "正常")
                    .withDetail("check_table", "user")
                    .build();
        } catch (Exception e) {
            // 检查失败,返回DOWN状态+异常信息
            return Health.down()
                    .withDetail("error", e.getMessage())
                    .withDetail("db_status", "异常")
                    .build();
        }
    }
}
3. 扩展默认数据库健康检查(仅补充信息)

若需保留默认检查(如连接池状态),可继承AbstractHealthIndicator

@Component
public class ExtendedDbHealthIndicator extends AbstractHealthIndicator {
    @Autowired
    private DataSource dataSource;

    @Override
    protected void doHealthCheck(Health.Builder builder) throws Exception {
        // 调用默认检查(如连接有效性)
        try (Connection conn = dataSource.getConnection()) {
            builder.up().withDetail("connection_url", conn.getMetaData().getURL());
        } catch (Exception e) {
            builder.down(e);
        }
        // 补充自定义检查(如慢查询数)
        int slowQueryCount = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM slow_query_log WHERE create_time > NOW() - INTERVAL 5 MINUTE", Integer.class);
        builder.withDetail("slow_query_count_5min", slowQueryCount);
    }
}

核心逻辑:实现HealthIndicator接口,在health()方法中编写自定义检查逻辑,通过Health.up()/down()返回健康状态,Actuator会自动聚合所有HealthIndicator的结果到/health端点。

2. MySQL Online DDL执行期间,ALGORITHM=COPY与INPLACE对业务的影响差异?

思路

从“锁表策略、数据拷贝、业务可用性”三个核心维度对比,明确不同场景的选型建议。

回答示例

MySQL Online DDL的ALGORITHM参数决定DDL的执行方式,COPYINPLACE对业务的影响差异显著:

特性

ALGORITHM=COPY

ALGORITHM=INPLACE

核心逻辑

拷贝原表数据到新表,DDL完成后替换原表

直接在原表上修改(仅重构数据/索引,无全量拷贝)

锁表策略

全程加表级写锁(WRITE LOCK),读正常/写阻塞

大部分场景仅加元数据锁(MDL),读/写基本不阻塞(仅短时间MDL锁)

数据拷贝

全量表拷贝,IO/CPU消耗大

无全量拷贝(索引重建仅处理索引数据),资源消耗小

业务影响

写操作长时间阻塞,适用于低峰期/小表

读写基本无感知,适用于生产环境/大表

典型场景

不支持INPLACE的DDL(如修改字段类型、字符集)

加索引、删索引、修改字段注释、调整自增值

空间占用

需额外1倍表空间(存储新表)

仅需少量临时空间(索引重建)

关键补充

  • INPLACE并非“无锁”:如修改字段长度(varchar(10)→varchar(20))仍会短时间阻塞写操作,但远短于COPY
  • 8.0版本引入INSTANT算法(部分DDL无需拷贝/修改数据,仅改元数据),比INPLACE更轻量。

3. Redis主从切换时,哨兵模式下客户端如何感知新主节点地址?

思路

讲哨兵的“主节点监控→故障判定→切换→通知客户端”全流程,核心是客户端的“哨兵监听+地址刷新”逻辑。

回答示例

Redis哨兵(Sentinel)模式下,客户端通过哨兵通知+地址刷新机制感知主节点切换,核心流程:

1. 哨兵侧核心动作
  1. 哨兵集群持续监控主节点(默认每1秒PING一次),判定主节点宕机(主观下线→客观下线);
  2. 哨兵集群选举出leader,执行主从切换(将最优从节点升级为新主节点);
  3. 切换完成后,哨兵通过发布订阅机制(频道+switch-master)广播新主节点地址(IP+端口)。
2. 客户端侧感知逻辑

主流客户端(Jedis/Lettuce)内置哨兵适配逻辑,步骤如下:

  1. 初始化时关联哨兵:客户端配置哨兵地址(而非直接配置主节点),启动时从哨兵获取当前主节点地址;
  2. 监听哨兵频道:客户端订阅哨兵的+switch-master频道,实时接收主节点切换通知;
  3. 自动刷新主节点地址
  4. 透明重试:切换过程中失败的命令,客户端自动重试新主节点(需业务保证幂等)。

示例(Jedis哨兵配置)

Set<String> sentinelNodes = new HashSet<>(Arrays.asList("127.0.0.1:26379", "127.0.0.1:26380"));
JedisPoolConfig poolConfig = new JedisPoolConfig();
JedisSentinelPool pool = new JedisSentinelPool("mymaster", sentinelNodes, poolConfig);
// 客户端自动从哨兵获取主节点,切换时自动刷新
Jedis jedis = pool.getResource();

核心:客户端不直接依赖主节点地址,而是通过哨兵动态获取,切换过程对业务透明(仅需处理短暂的重试/超时)。

4. RabbitMQ死信队列(DLQ)触发条件及消息流转路径?

思路

先明确死信的触发条件,再拆解“原队列→死信交换机→死信队列”的流转路径,结合示例配置说明。

回答示例

死信队列(DLQ)是存储“无法正常消费”消息的队列,核心触发条件和流转路径如下:

1. 死信触发条件(满足任一即触发)
  1. 消息被拒绝(Reject/Nack)且不重入:消费者调用basicReject/basicNack,且参数requeue=false
  2. 消息过期:队列设置x-message-ttl(消息过期时间),或消息本身设置过期时间,超时未消费;
  3. 队列达到最大长度:队列设置x-max-length,消息数量超限,最早的消息被挤入死信队列。
2. 消息流转路径
graph LR
A[生产者] --> B[原队列(配置死信参数)]
B --> C{正常消费?}
C -- 否(触发死信条件) --> D[死信交换机(DLX)]
D --> E[死信队列(DLQ)]
C -- 是 --> F[消费者]
E --> G[死信消费者(人工处理/重试)]
3. 核心配置(原队列绑定死信参数)
// 1. 声明死信交换机(DLX)
channel.exchangeDeclare("dlx.exchange", BuiltinExchangeType.DIRECT, true);
// 2. 声明死信队列(DLQ)
channel.queueDeclare("dlq.queue", true, false, false, null);
// 3. 绑定死信队列到死信交换机
channel.queueBind("dlq.queue", "dlx.exchange", "dlx.routing.key");

// 4. 声明原队列,配置死信参数
Map<String, Object> args = new HashMap<>();
args.put("x-dead-letter-exchange", "dlx.exchange"); // 绑定死信交换机
args.put("x-dead-letter-routing-key", "dlx.routing.key"); // 死信路由键
args.put("x-message-ttl", 60000); // 消息过期时间60s
args.put("x-max-length", 1000); // 队列最大长度1000
channel.queueDeclare("origin.queue", true, false, false, args);

关键:死信队列需提前声明,原队列通过参数绑定死信交换机/路由键,消息成为死信后自动路由到死信队列。

5. JVM参数-XX:MaxMetaspaceSize未设置时,元空间OOM的典型场景?

思路

先说明MaxMetaspaceSize默认值(无上限,受物理内存限制),再拆解OOM的核心触发场景,结合JVM内存管理逻辑说明。

回答示例

-XX:MaxMetaspaceSize默认未设置时,元空间(Metaspace)理论上无上限(仅受操作系统物理内存限制),但仍会触发OutOfMemoryError: Metaspace,典型场景:

1. 动态生成大量类且类加载器未释放
  • 场景:频繁使用动态代理(Spring AOP、MyBatis Mapper)、ASM字节码生成、Groovy/JSP动态编译,生成大量类元数据;

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

本专栏在精不在多,内容分为八股文、大厂真实面经,面试通过后将offer和面试题私发给我,可退还专栏的收益部分费用。欢迎大家共建专栏

全部评论
27届拼多多实习机会或看我主页 https://careers.pddglobalhr.com/campus/intern?t=4OmKPVeX9a
点赞 回复 分享
发布于 今天 17:59 上海
SpringBootActuator这块问得挺细的,自定义HealthIndicator确实是实际业务中常用的扩展点。看你面经准备得很系统,从源码到场景都有覆盖。现在纯后端背景转AI应用开发其实挺有优势的,我们团队招AI应用研发实习生,工程能力强的同学很受欢迎。暑期实习还有HC,JD可以参考:https://www.nowcoder.com/jobs/detail/440929?jobId=440929
点赞 回复 分享
发布于 今天 15:35 浙江

相关推荐

牛客44320985...:你的当务之急是把这个糖的要死的沟槽ide主题改了
点赞 评论 收藏
分享
03-17 23:54
黑龙江大学 Java
来个白菜也好啊qaq:可以的,大厂有的缺打手
点赞 评论 收藏
分享
泥给路哒油:真的不行了,以后趋势就是没有前后端职位之分了,我现在就是什么都干,有了ai就能干全栈,md年初目送一大堆同事毕业
点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
正在热议
更多
# 春招至今,你的战绩如何? #
8542次浏览 77人参与
# 你的实习产出是真实的还是包装的? #
1566次浏览 40人参与
# 巨人网络春招 #
11282次浏览 223人参与
# 军工所铁饭碗 vs 互联网高薪资,你会选谁 #
7307次浏览 40人参与
# 简历第一个项目做什么 #
31456次浏览 321人参与
# 当下环境,你会继续卷互联网,还是看其他行业机会 #
186738次浏览 1118人参与
# 米连集团26产品管培生项目 #
5465次浏览 213人参与
# 不考虑薪资和职业,你最想做什么工作呢? #
152219次浏览 887人参与
# 研究所笔面经互助 #
118829次浏览 577人参与
# 重来一次,我还会选择这个专业吗 #
433244次浏览 3926人参与
# 简历中的项目经历要怎么写? #
309873次浏览 4177人参与
# 面试紧张时你会有什么表现? #
30461次浏览 188人参与
# 你今年的平均薪资是多少? #
212936次浏览 1039人参与
# AI时代,哪些岗位最容易被淘汰 #
63185次浏览 789人参与
# 我的求职精神状态 #
447929次浏览 3128人参与
# 你最满意的offer薪资是哪家公司? #
76370次浏览 374人参与
# 正在春招的你,也参与了去年秋招吗? #
363068次浏览 2635人参与
# 你怎么看待AI面试 #
179715次浏览 1222人参与
# 牛客AI文生图 #
21391次浏览 237人参与
# 职能管理面试记录 #
10774次浏览 59人参与
# 网易游戏笔试 #
6438次浏览 83人参与
# 腾讯音乐求职进展汇总 #
160532次浏览 1109人参与
牛客网
牛客网在线编程
牛客网题解
牛客企业服务