产生背景
使用SpringBoot 集成Quartz框架,项目启动时报错:
2020-08-12 13:49:13.003 ERROR 8512 --- [eduler_Worker-3] org.quartz.core.JobRunShell : Job test-group.test threw an unhandled Exception:
java.lang.ClassCastException: cn.bupt.zcc.dynamicquartz.model.ScheduleJob cannot be cast to cn.bupt.zcc.dynamicquartz.model.ScheduleJob
我眯着眼睛瞅了几遍,并在项目中进行全局搜索,确定类限定名是完全一致!一时想不出啥原因,于是寻求度娘帮助,找到了这篇博文,参考链接: link.
Java 中,判断两个类型是否相同需要:1.两个类有相同的限定名;2.两个类由同一类加载器实例加载。既然类限定名是没有问题的,那么只能说明要强转成的 TypeA 和从 memcached 中取回的 TypeA(Java 标准反序列化生成的实例的 class)不是由同一类加载器实例加载的。后来查了一下,果不其然,同事写的那段逻辑是用 spring-devtool 启动的,而 spring-devtool 自己实现了一个类加载器,这个类加载器默认加载所有自己写的 Java 代码编译出来的 .class (也就是非 .jar 中的 .class),加载要强转为的 TypeA 就是由他加载的。而 memcached 中取回 TypeA 这块的逻辑是在 .jar 中封包的,这部分是由 AppClassLoader 加载的。这样就造成了同样是 TypeA,由不同类加载器实例(别提实例了,类加载器的类都不同)加载出来的情况,因此,他们虽然名字一样,但是已经不是一个类了,所以不能强转成功了。
发生错误时的代码:
package cn.bupt.zcc.dynamicquartz.job;
import cn.bupt.zcc.dynamicquartz.model.ScheduleJob;
import cn.bupt.zcc.dynamicquartz.service.QuartzService;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Service;
/**
*
*
* @author: Even
* @create:
**/
@Service("quartzJobFactory")
public class QuartzJobFactory extends QuartzJobBean {
@Autowired
QuartzService quartzService;
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
// ScheduleJob object = (ScheduleJob) jobExecutionContext.getMergedJobDataMap().get("scheduleJob");
/**
* 自己不能强转成自己我是没想到的
*/
ScheduleJob object = (ScheduleJob) jobExecutionContext.getMergedJobDataMap().get("scheduleJob");
if(object.getMethodName()==null || object.getMethodName().equals("")){
quartzService.executeTask(object.getBeanName());
}else {
quartzService.executeTask(object.getBeanName(),object.getMethodName());
}
}
}
jobExecutionContext.getMergedJobDataMap().get(“scheduleJob”);得到PostgreSQL数据库bytea的job_data字段反序列化出来的对象和SpringBoot devtools 加载的ScheduleJob 不是同一个类的实例
解决方法
不使用Springboot devtools,将其在pom.xml中注释掉
<!--<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
<scope>true</scope>
</dependency>-->
重启项目,不再报ClassCastException了