quartz任务加载的问题 麻烦近来看看
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了quartz任务加载的问题 麻烦近来看看相关的知识,希望对你有一定的参考价值。
任务在servlet的init加载的时候出现了下面那个错误,请问那个表是做什么的呢?这个错误应该如何解决,是否是配置问题,麻烦知道的告诉我一下 谢谢 (那个表我没有手动插过值,都是配置文件自动插入的)
ErrorLogger [ERROR] An error occured while scanning for the next trigger to fire.
org.quartz.JobPersistenceException: Couldn't acquire next trigger: ORA-01400: 无法将 NULL 插入 ("BOCMIS"."QRTZ_FIRED_TRIGGERS"."PRIORITY")
[See nested exception: java.sql.SQLException: ORA-01400: 无法将 NULL 插入 ("BOCMIS"."QRTZ_FIRED_TRIGGERS"."PRIORITY")
]
at org.quartz.impl.jdbcjobstore.JobStoreSupport.acquireNextTrigger(JobStoreSupport.java:1778)
at org.quartz.impl.jdbcjobstore.JobStoreTX.acquireNextTrigger(JobStoreTX.java:1218)
at org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java(Compiled Code))
* Nested Exception (Underlying Cause) ---------------
java.sql.SQLException: ORA-01400: 无法将 NULL 插入 ("BOCMIS"."QRTZ_FIRED_TRIGGERS"."PRIORITY")
下面是配置
org.quartz.scheduler.instanceName = DefaultQuartzScheduler
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.wrapJobExecutionInUserTransaction = false
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
org.quartz.jobStore.misfireThreshold = 60000
first to create tables
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.dataSource = qzDS
org.quartz.dataSource.qzDS.driver = oracle.jdbc.driver.OracleDriver
org.quartz.dataSource.qzDS.URL = jdbc:oracle:thin:@localhost:test
org.quartz.dataSource.qzDS.user = test
org.quartz.dataSource.qzDS.password = test
org.quartz.dataSource.qzDS.maxConnections = 30
JVM的深入理解:由一次Quartz的定时任务引发的“A cannot cast to A”的问题
由Quartz框架引发的“A cannot cast to A”的问题
起因与问题描述
向新开的项目中添加定时任务,部署集群,添加了热加载(springboot-dev-tools),发现在转型时候出现了A cannot cast to A”的问题。自己怎么可能不认识自己???排查走起!!!
排查
类确实是同一类,问题会出现在哪里呢?我们可以想到,类加载器不同会导致“我不是我”的问题,所以打印debug走起!
真的是类加载器不同!能注意到,我们想要的ScheduleJobEntity类,类加载器是RestartClassLoader,这一切发生在【添加热加载(springboot-dev-tools)】之后才出现的。这时候需要复习一下springboot-dev-tools与类加载器机制的知识了。
知识回顾
类加载器机制
- 有两个术语,一个叫“定义类加载器”,一个叫“初始类加载器”。比如有如下的类加载器结构:
- bootstrap
- ExtClassloader
- AppClassloader
- -自定义clsloadr1
- -自定义clsloadr2
如果用“自定义clsloadr1”加载java.lang.String类,那么根据双亲委派最终bootstrap会加载此类,那么bootstrap类就叫做该类的“定义类加载器”,而包括bootstrap的所有得到该类class实例的类加载器都叫做“初始类加载器”。
- bootstrap
- 所说的“命名空间”,是指jvm为每个类加载器维护的一个“表”,这个表记录了所有以此类加载器为“初始类加载器”(而不是定义类加载器,所以一个类可以存在于很多的命名空间中)加载的类的列表,所以,题目中的问题就可以解释了:
CLTest是AppClassloader加载的,String是通过加载CLTest的类加载器也就是AppClassloader进行加载,但最终委派到bootstrap加载的(当然,String类其实早已经被加载过了,这里只是举个例子)。所以,对于String类来说,bootstrap是“定义类加载器”,AppClassloader是“初始类加载器”。根据刚才所说,String类在AppClassloader的命名空间中(同时也在bootstrap,ExtClassloader的命名空间中,因为bootstrap,ExtClassloader也是String的初始类加载器),所以CLTest可以随便访问String类。这样就可以解释“处在不同命名空间的类,不能直接互相访问”这句话了。 - 一个类,由不同的类加载器实例加载的话,会在方法区产生两个不同的类,彼此不可见,并且在堆中生成不同Class实例。
- 那么由不同类加载器实例(比如-自定义clsloadr1,-自定义clsloadr2)所加载的classpath下和ext下的类,也就是由我们自定义的类加载器委派给AppClassloader和ExtClassloader加载的类,在内存中是同一个类吗?所有继承ClassLoader并且没有重写getSystemClassLoader方法的类加载器,通过getSystemClassLoader方法得到的AppClassloader都是同一个AppClassloader实例,类似单例模式。在ClassLoader类中getSystemClassLoader方法调用私有的initSystemClassLoader方法获得AppClassloader实例,在initSystemClassLoader中:
sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
...
scl = l.getClassLoader();
AppClassloader是sun.misc.Launcher类的内部类,Launcher类在new自己的时候生成AppClassloader实例并且放在自己的私有变量loader里:
loader = AppClassLoader.getAppClassLoader(extclassloader);
值得一提的是sun.misc.Launcher类使用了一种类似单例模式的方法,即既提供了单例模式的接口getLauncher()又把构造函数设成了public的。但是在ClassLoader中是通过单件模式取得的Launcher 实例的,所以我们写的每个类加载器得到的AppClassloader都是同一个AppClassloader类实例。
这样的话得到一个结论,就是所有通过正常双亲委派模式的类加载器加载的classpath下的和ext下的所有类在方法区都是同一个类,堆中的Class实例也是同一个。
springboot-dev-tools
可以参考<a href = "https://blog.csdn.net/isea533/article/details/70495714">Spring DevTools 介绍一文,其中最关键的一句话就是
重启功能是通过使用两个类加载器实现的。 对于大多数应用程序,此方法运行良好,但有时可能会导致类加载问题。
默认情况下,IDE中的任何打开的项目都会使用“restart”类加载器加载,任何常规.jar文件将使用“base”类加载器加载。
解决问题
在项目 /resource/META-INF目录下(如果没有就创建一个)创建
spring-devtools.properties文件 加入下面代码:
restart.include.mapper=/mapper-[w-.]+jar
restart.include.pagehelper=/pagehelper-[w-.]+jar
restart.include.shiro=/shiro-[w-.]+jar
这里其实是
添加 jar 包到 restart 类加载器中 = 后面是具体的 jar 包名称, 或正则表达式
以上是关于quartz任务加载的问题 麻烦近来看看的主要内容,如果未能解决你的问题,请参考以下文章