线程依赖注入问题排查:SQL查询返回NULL触发异常解决方案
问题排查与解决方案:原型线程类注入Repository后查询返回NULL异常
问题梳理
Spring环境中,原型作用域的ExtrusionProcessThread(继承自Thread)注入FiscalCalendarRepository后,执行run方法调用其findReadingVariables查询SQL Server数据库时,extrusionL1DataList返回NULL并触发异常。
排查步骤
- 验证Repository注入有效性:检查
ExtrusionProcessThread实例是否由Spring容器创建,手动new的实例不会触发Spring依赖注入,会导致fiscalCalendarRepository为NULL,调用方法时触发空指针异常。可在run方法开头打印fiscalCalendarRepository引用确认是否为空。 - 检查Repository方法异常处理:当前
findReadingVariables仅捕获EmptyResultDataAccessException,但JDBC操作可能抛出SQL语法错误、数据库连接异常、结果集映射异常等其他未捕获异常,这些异常会直接向上抛出,导致方法无返回值,最终extrusionL1DataList被赋值为NULL。 - 验证数据库查询有效性:直接执行
SELECT * FROM SPC.dbo.manager_l1语句,确认数据库中是否存在数据,以及表名、字段是否与ReadingProcessResponseMapper的映射逻辑匹配。
解决方案
1. 修复Repository方法的异常处理
扩大异常捕获范围,确保任何情况下都返回非NULL的List:
@Override public List<ReadingProcessResponse> findReadingVariables() { StringBuilder query = new StringBuilder(); query.append("SELECT * FROM SPC.dbo.manager_l1"); try { return jdbcTemplate.query(query.toString(), new ReadingProcessResponseMapper()); } catch (EmptyResultDataAccessException e) { return new ArrayList<>(); } catch (Exception e) { // 捕获所有JDBC相关异常 e.printStackTrace(); return new ArrayList<>(); } }
2. 确保线程实例由Spring容器创建
- 避免手动
new线程实例,通过ApplicationContext.getBean(ExtrusionProcessThread.class)获取原型Bean,确保Spring完成依赖注入。 - 改用构造器注入所有依赖,确保实例化时依赖已注入:
@Component @Scope("prototype") public class ExtrusionProcessThread extends Thread{ // 省略其他字段 private final FiscalCalendarRepository fiscalCalendarRepository; @Autowired public ExtrusionProcessThread(FiscalCalendarRepository fiscalCalendarRepository, ReadingProcessRepository readingProcessRepository, ManagerExtrusionL1Repository managerExtrusionL1Repository, ManagerExtrusionL3Repository managerExtrusionL3Repository, EmailService emailService) { this.fiscalCalendarRepository = fiscalCalendarRepository; this.readingProcessRepository = readingProcessRepository; this.managerExtrusionL1Repository = managerExtrusionL1Repository; this.managerExtrusionL3Repository = managerExtrusionL3Repository; this.emailService = emailService; } // 省略run方法 }
3. 替换Thread继承为Runnable实现(推荐)
Spring生态中更推荐实现Runnable接口,配合TaskExecutor管理线程,避免直接继承Thread带来的容器管理问题:
@Component @Scope("prototype") public class ExtrusionProcessTask implements Runnable { // 字段与原类一致,构造器注入依赖 @Override public void run() { // 原run方法逻辑不变 } }
使用时通过Spring的TaskExecutor提交任务:
@Autowired private TaskExecutor taskExecutor; @Autowired private ApplicationContext context; public void startTask(ReadingProcessData data) { ExtrusionProcessTask task = context.getBean(ExtrusionProcessTask.class); task.setData(data); // 设置必要参数 taskExecutor.execute(task); }
4. 补充空值检查
在run方法中添加空值判断,避免后续逻辑因NULL列表触发异常:
if (data.getLine().equals(LineEnum.LINE_1.getCodeLine())) { extrusionL1DataList = fiscalCalendarRepository.findReadingVariables(); if (extrusionL1DataList == null) { extrusionL1DataList = new ArrayList<>(); } } else { extrusionL3DataList = readingProcessRepository.findReadingVariables(PlcVariablesMySqlEnum.TABLE_EXTRUSION_L3.getDescription()); if (extrusionL3DataList == null) { extrusionL3DataList = new ArrayList<>(); } }
内容的提问来源于stack exchange,提问作者KING
相关产品推荐
相关产品推荐

