接入OptaPlanner的Spring考试排期应用启动报ClassCastException
Spring+OptaPlanner考试排期应用启动报错排查指南
启动报错信息
Exception in thread "main" java.lang.ClassCastException: class org.springframework.boot.context.event.ApplicationStartingEvent cannot be cast to class org.springframework.boot.context.event.ApplicationPreparedEvent (org.springframework.boot.context.event.ApplicationStartingEvent and org.springframework.boot.context.event.ApplicationPreparedEvent are in unnamed module of loader 'app')
报错根因
这个类转换异常属于Spring Boot上下文加载阶段的生命周期事件分发逻辑出错,和OptaPlanner排期的业务求解逻辑无直接关联,常见触发点为:
- Spring Boot核心依赖与引入的第三方Starter(含OptaPlanner Spring Boot Starter)版本不兼容,导致事件广播器的类型处理逻辑错乱
- 项目中自定义的ApplicationListener实现存在泛型声明错误,未做类型判断就对接收的事件对象做强转
现有代码存在的隐性问题(即使启动成功也会触发后续运行异常)
包路径拼写混乱
- 排期方案类
Timetable放在models包下 - 控制器类中导入的排期方案类路径为
modeles.Timetable(存在多字母e的拼写错误) - 启动主类也放在
models包下
这种拼写近似但不统一的包路径,会导致类重复加载、组件扫描失效,间接触发类转换类异常。
排期方案类构造方法定义错误
当前代码中写的带参初始化方法:
public void TimeTable(List<Periode> periodeList, List<Salle> roomList, List<Examen> examenList)
不属于类构造方法:
- 带了
void返回值,本质是普通成员方法 - 方法名
TimeTable和类名Timetable大小写不匹配 - 缺失OptaPlanner要求的公开无参构造方法
组件扫描范围配置错误
@SpringBootApplication默认扫描启动类所在包及所有子包的组件,当前启动类放在models包下,如果其他业务实体、OptaPlanner自动配置类分布在其他路径下,会出现扫描不到Bean、上下文加载失败的问题。
依赖配置缺失
代码中通过@Autowired注入SolverManager,如果未引入对应版本的OptaPlanner Spring Boot Starter,容器中根本不会自动注册这个Bean,会触发依赖注入失败异常。
分步解决操作
- 对齐依赖版本:确保OptaPlanner Spring Boot Starter的版本与项目使用的Spring Boot版本兼容,不混用跨大版本的依赖
- 统一包路径结构:将启动主类放在项目根包路径下(例如
com.exam.timetable),修正控制器类中的包名拼写错误,保证所有业务类、组件都在根包的子路径下,被Spring组件扫描正常加载 - 修正排期方案类定义:删除带void的错误初始化方法,补充公开无参构造方法;如果需要带参初始化逻辑,单独定义和类名完全一致的带参构造方法,去掉void返回值
- 排查自定义监听器:检查项目中所有实现
ApplicationListener的类,修正泛型声明,避免对未匹配类型的事件对象直接强转 - 分步验证启动流程:先暂时注释控制器中的业务注入逻辑,确认Spring上下文可以正常加载,排查完启动类转换异常后,再逐步放开OptaPlanner的相关配置
内容的提问来源于stack exchange,提问作者Light Yagami
相关产品推荐
相关产品推荐

