一段让服务直接不可用的代码

背景 
     

  其它厂家调用我们应用的接口把处理后的数据回传过来,是http 协议的接口,这边会进行入库下载文件的逻辑,比较耗时,为了防止服务的阻塞,这边接受到数据进行了简单的校验后构建了一个本地队列,然后开启一个一直消费这个队列的功能,问题就是在实现这个功能的过程中产生。


实现

@PostConstruct
    public void consume() {
        while (!Thread.currentThread().isInterrupted()) {
            AlgorithmAlarmReviewRecordDTO algorithmAlarmReviewRecordDTO = alarmReviewDataQueue.poll();
            if (algorithmAlarmReviewRecordDTO == null) {
                continue;
            }
            List<PointInfo> pointInfo = algorithmAlarmReviewRecordDTO.getPointInfo();
            String stationCode = algorithmAlarmReviewRecordDTO.getStationCode();
            StationInfoDTO stationInfoDTO = stationApiService.searchByPmsCode(stationCode);
            if (CollectionUtil.isEmpty(pointInfo)) {
                log.error("点位信息为空 pointInfo is null");
                return;
            }
            for (PointInfo info : pointInfo) {
                List<AlarmInfo> alarmInfo = info.getAlarmInfo();
                if (CollectionUtil.isEmpty(alarmInfo)) {
                    log.error("报警信息为空 alarmInfo is null");
                    return;
                }
                for (AlarmInfo alarm : alarmInfo) {
                    AlgorithmAlarmReviewRecord algorithmAlarmReviewRecord = new AlgorithmAlarmReviewRecord();
                    BeanUtils.copyProperties(algorithmAlarmReviewRecordDTO, algorithmAlarmReviewRecord);
                    algorithmAlarmReviewRecord.setTaskRecordTime(DateUtil.str2Timestamp(algorithmAlarmReviewRecordDTO.getTaskRecordTime()));
                    algorithmAlarmReviewRecord.setAreaName(info.getAreaName());
                    algorithmAlarmReviewRecord.setBayName(info.getBayName());
                    algorithmAlarmReviewRecord.setPointId(info.getPointId());
                    algorithmAlarmReviewRecord.setPointName(info.getPointName());
                    algorithmAlarmReviewRecord.setRectangle(alarm.getRectangle());
                    algorithmAlarmReviewRecord.setAlarmState(alarm.getAlarmState());
                    //alarm.getImageBase64()
                    String fileId = handleImage(stationInfoDTO, alarm.getImageBase64());
                    algorithmAlarmReviewRecord.setFileId(fileId);
                    algorithmAlarmReviewRecord.setTime(DateUtil.str2Timestamp(alarm.getTime()));
                    algorithmAlarmReviewRecordMapper.insert(algorithmAlarmReviewRecord);
                }

            }
        }
    }

现象

        postman 调用不了接口,定睛一看服务一直启动不成功。

整改

@PostConstruct
public void consume() {
	Thread consumerThread = new Thread(() -> {
		while (!Thread.currentThread().isInterrupted()) {
			AlgorithmAlarmReviewRecordDTO algorithmAlarmReviewRecordDTO = alarmReviewDataQueue.poll();
			if (algorithmAlarmReviewRecordDTO == null) {
				ThreadUtil.safeSleep(1000);
				continue;
			}
			try {
				List<PointInfo> pointInfo = algorithmAlarmReviewRecordDTO.getPointInfo();
				String stationCode = algorithmAlarmReviewRecordDTO.getStationCode();
				StationInfoDTO stationInfoDTO = stationApiService.searchByPmsCode(stationCode);
				if (CollectionUtil.isEmpty(pointInfo)) {
					log.error("点位信息为空 pointInfo is null");
					continue;
				}
				for (PointInfo info : pointInfo) {
					List<AlarmInfo> alarmInfo = info.getAlarmInfo();
					if (CollectionUtil.isEmpty(alarmInfo)) {
						log.error("报警信息为空 alarmInfo is null");
						continue;
					}
					for (AlarmInfo alarm : alarmInfo) {
						AlgorithmAlarmReviewRecord algorithmAlarmReviewRecord = new AlgorithmAlarmReviewRecord();
						BeanUtils.copyProperties(algorithmAlarmReviewRecordDTO, algorithmAlarmReviewRecord);
						algorithmAlarmReviewRecord.setStationId(stationInfoDTO.getStationId());
						algorithmAlarmReviewRecord.setTaskRecordTime(DateUtil.str2Timestamp(algorithmAlarmReviewRecordDTO.getTaskRecordTime()));
						algorithmAlarmReviewRecord.setAreaName(info.getAreaName());
						algorithmAlarmReviewRecord.setBayName(info.getBayName());
						algorithmAlarmReviewRecord.setMainDeviceName(info.getMainDeviceName());
						algorithmAlarmReviewRecord.setComponentName(info.getComponentName());
						algorithmAlarmReviewRecord.setPointId(info.getPointId());
						algorithmAlarmReviewRecord.setPointName(info.getPointName());
						algorithmAlarmReviewRecord.setDefectType(alarm.getDefectType());
						algorithmAlarmReviewRecord.setTime(DateUtil.str2Timestamp(alarm.getTime()));
						algorithmAlarmReviewRecord.setRectangle(alarm.getRectangle());
						algorithmAlarmReviewRecord.setAlarmState(alarm.getAlarmState());
						String fileId = handleImage(stationInfoDTO, alarm.getImageBase64());
						algorithmAlarmReviewRecord.setFileId(fileId);
						algorithmAlarmReviewRecord.setCreateTime(System.currentTimeMillis());
						algorithmAlarmReviewRecordMapper.insert(algorithmAlarmReviewRecord);
					}
				}
			} catch (Exception e) {
				log.error("处理告警审核数据报错:{},{}", e, e.getMessage());
			}
		}
	});
	consumerThread.setName("alarm-review-data-consumer");
	consumerThread.start();
}

原因

        项目启动不成功是因为你在 @PostConstruct 方法中使用了无限循环,这会阻塞应用的启动过程。@PostConstruct 注解的方法在 Spring 容器初始化完成后立即执行,并且必须执行完毕后应用才能完全启动。
问题分析:
@PostConstruct 方法中的无限循环会阻止 Spring Boot 应用完成启动
即使添加了 Thread.currentThread().isInterrupted() 检查,主线程也不会被中断,所以循环不会停止
这导致应用无法完成初始化,外部请求(如 Postman)无法被处理

总结

      修改要点:
将无限循环包装在独立的线程中执行
给线程设置有意义的名称,便于调试和监控
添加异常处理机制,防止线程因异常而终止
在队列为空时添加短暂休眠,避免CPU空转
在异常情况下也添加休眠,防止异常频繁重试
这样修改后,Spring Boot 应用应该能够正常启动,因为 @PostConstruct 方法会立即返回,而消费逻辑在独立线程中执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值