由于工作,quartz需要持久化在数据库中,开启每日凌晨定时任务,在任务处理job中又需要使用到spring管理的service类,故遇到了几个小问题,以此做个记录。
- 配置spring-quartz文件时,使用的MethodInvokingJobDetailFactoryBean创建jobDetail
由于quartz使用了持久化,JobStoreTX存储方式,导致NotSerializableException异常。谷歌得知MethodInvokingJobDetailFactoryBean并未实现序列化,使用JobDetailFactoryBean方式创建,并在job类继承QuartzJobBean,创建jobDetail便不会出错。如下:
<!--使用JobDetailFactoryBean可序列化创建jobDetail-->
<!--注入job,生成jobdetail-->
<bean id="autoJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.pabj.newzg.xzg.message.utils.quartz.job.TimeQueryContract" />
<!--持久化设置,允许持久化-->
<property name="durability" value="true" />
</bean>
——————————————————————————————————————————————————————————————————————————————————
//继承QuartzJobBean 类
@DisallowConcurrentExecution
public class TimeQueryContract extends QuartzJobBean {
/**
* Execute the actual job. The job data map will already have been
* applied as bean property values by execute. The contract is
* exactly the same as for the standard Quartz execute method.
*
* @param context
* @see #execute
*/
@Override
protected void executeInternal(JobExecutionContext context) {...}
}
- 注入spring管理的service的服务到job定时操作中,直接@Resource注入
当时是直接报NullPointerException空指针异常,后又谷歌得知quartz有自己的上下文,spring管理不到,当然无法自动注入,改用在spring-quartz配置文件中直接将此service添加到jobDataMap中,
<!--注入job,生成jobdetail-->
<bean id="autoJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.pabj.newzg.xzg.message.utils.quartz.job.TimeQueryContract" />
<!--持久化设置,允许持久化-->
<property name="durability" value="true" />
<!-- 将service添加到jobDataMap中,直接在job中通过context获取-->
<property name="jobDataAsMap">
<map>
<entry key="contractSignService" value-ref="contractSignServiceImpl" />
</map>
</property>
</bean>
这是一个方式可以解决没有持久化的quartz的service注入问题。但由于我的配置是需要持久化的,也就是需要存入数据库,需要序列化jobDetail。但spring的service底层没有实现Serializable接口,故报错NotSerializableException,自己实现Serializable也没用,其后谷歌很久,有重写相关类的方法,和使用sessionfactory,但本人能力还不行,没采用。后终在一位博主那看到将spring的context注入到quartz中
- 在配置SchedulerFactoryBean时可注入spring上下文
<!--使用spring的Scheduler创建方式-->
<bean name="scheduler"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<!--引用spring的数据源-->
<property name="dataSource" ref="dataSource" />
<!--读取quartz基本配置-->
<property name="configLocation" value="classpath:quartz.properties" />
<!--在此申明注入spring的上下文!!!-->
<property name="applicationContextSchedulerContextKey"
value="applicationContextKey" />
<!--设置自动启动-->
<property name="autoStartup" value="true" />
<!--动态修改存在的job-->
<property name="overwriteExistingJobs" value="true" />
<!--直接注入凌晨定时查询合同的job和trigger-->
<property name="triggers">
<list>
<ref bean="createTrigger" />
</list>
</property>
</bean>
————————————————————————————————————————————————————————————————————————————————————————
//在job中获取到spring上下文进行service调用
@DisallowConcurrentExecution
public class TimeQueryContract extends QuartzJobBean {
/**
* Execute the actual job. The job data map will already have been
* applied as bean property values by execute. The contract is
* exactly the same as for the standard Quartz execute method.
*
* @param context
* @see #execute
*/
@Override
protected void executeInternal(JobExecutionContext context) {
System.out.println("开始执行合同日期查询...");
try {
//获取spring上下文
ApplicationContext applicationContextKey = (ApplicationContext) context.getScheduler().getContext().get("applicationContextKey");
//获取service服务
ContractSignServiceImpl contractSignService = (ContractSignServiceImpl) applicationContextKey.getBean("contractSignServiceImpl");
System.out.println(contractSignService.queryDate().toString());
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
走到这步,就解决了我快谷歌一天的难题。目前大概了解如此,算是解决了问题,做个记录,增强印象