写在前面:
前面有简单的记录下Timer定时的用法,但是在此次项目中,选择的是quartz来完成定时操作任务的。两者都可以完成定时操作,但是spring可以整合quartz,并且配置起来也比较简便,还可以同时跑多个任务。就选择了quartz,quartz的用法也很强大,这里也是简单的记录下。
第一步还是需要写自己的任务类,如果有涉及到对数据库的增删改查操作,就按照正常的action,service ,dao的三层来编写方法就好,只不过现在不是通过页面发送请求来调用action,而是通过quartz的定时来调用action操作。
1.编写自己的任务类:
@Controller("TimerTask") public class TimerTask { @Resource private ProjectWorkItemAssignmentService projectWorkItemAssignmentService; /** * 每天12:00去自动暂停ProjectWorkItemAssignment表中在执行的workItem * 以及去自动暂停WorkHoursRecord表中当天在执行的workItem */ public void autoPauseWorkItemOne() throws Exception{ projectWorkItemAssignmentService.autoPauseWorkItemOne(); } /** * 每天13:30去自动开启ProjectWorkItemAssignment表中在执行的workItem * 以及去自动开启WorkHoursRecord表中当天在执行的workItem */ public void autoStartWorkItem() throws Exception{ projectWorkItemAssignmentService.autoStartWorkItem(); } /** * 每天17:30去自动暂停ProjectWorkItemAssignment表中在执行的workItem * 以及去自动暂停WorkHoursRecord表中当天在执行的workItem */ public void autoPauseWorkItemTwo() throws Exception{ projectWorkItemAssignmentService.autoPauseWorkItemTwo(); } }
这里的任务类,我是当做action来写的,然后里面的业务方法,根据自己的需求来即可,这里只是简单的列举一下子,后面对应的service,dao的业务就不具体上代码了
2.编写配置文件,这里我用到的是使用配置文件的形式来配置程序执行的周期以及频率的(可以使用代码的,自己下去查阅资料),由于spring可以整合quartz,还是挺方便的。
我们可以把quartz的配置写在applicationContext.xml文件里面,也可以单独拿出来写一个,然后导入到applicationContext.xml文件中。这里就单独写一个文件。
applicationContext-quartz.xml(这里我自己配置了三个定时任务,可以根据自己的需要去开启配置)
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="TimerTask" /> <!-- 配置调度的定时任务 --> <property name="targetMethod" value="autoPauseWorkItemOne" /> <!-- 配置调度定时任务中的方法 --> <property name="concurrent" value="false" /> <!-- 是否并发执行 --> </bean> <bean id="jobDetail2" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="TimerTask" /> <!-- 配置调度的定时任务 --> <property name="targetMethod" value="autoStartWorkItem" /> <!-- 配置调度定时任务中的方法 --> <property name="concurrent" value="false" /> <!-- 是否并发执行 --> </bean> <bean id="jobDetail3" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="TimerTask" /> <!-- 配置调度的定时任务 --> <property name="targetMethod" value="autoPauseWorkItemTwo" /> <!-- 配置调度定时任务中的方法 --> <property name="concurrent" value="false" /> <!-- 是否并发执行 --> </bean> <!-- 触发器 配置定时任务的调度的时间 --> <bean id="workItemTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail" ref="jobDetail" /> <property name="cronExpression"> <value>0 0 12 * * ? </value><!-- [秒] [分] [时] [日] [月] [年] 每天12点触发--> </property> </bean> <bean id="workItemTrigger2" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail" ref="jobDetail2" /> <property name="cronExpression"> <value>0 30 13 * * ? </value><!-- [秒] [分] [时] [日] [月] [年] 每天13:30点触发--> </property> </bean> <bean id="workItemTrigger3" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail" ref="jobDetail3" /> <property name="cronExpression"> <value>0 30 17 * * ? </value><!-- [秒] [分] [时] [日] [月] [年] 每天17:30点触发--> </property> </bean> <!--定义调度器 --><!-- lazy-init='false'容器启动就会执行调度程序 autowire="no"--> <bean id="workItemscheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" lazy-init="false" autowire="no"> <property name="triggers"> <list> <ref bean="workItemTrigger" /> <ref bean="workItemTrigger2" /> <ref bean="workItemTrigger3" /> </list> </property> </bean> </beans>
记得在spring的配置文件中加入quartz的配置文件
applicationContext.xml:
<import resource="classpath:configs/applicationContext-quartz.xml"/>
对于调用任务类有两种方式,(使用JobDetailBean来调用某个类,)这里我用的是直接执行某个类的哪一个方法,比较方便。
其实在刚开始编写的过程中也遇到各种问题,下面也简单的记录下。
当任务类是service层的类时,无法使用getCurrentSession()来获取session,程序不报错,直接卡在那里。然后是可以使用openSession()来重新打开一个session的,但是对于增删改,每次都需要自己手动进行session的关闭以及事务的提交,不是很方便。当时一直没有找到问题所在,为什么不可以使用getCurrentSession,虽然quartz是新开了一个线程,但是getCurrentSession()不是获取当前线程的session,如果没有就重新开一个么?为什么获取不到呢?很是郁闷.......后来考虑到了是不是项目配置的session的生命周期有影响,因为项目延长了session的生命周期,如下:
<!-- 配置Spring的OpenSessionInViewFilter,以解决懒加载问题 --> <filter> <filter-name>OpenSessionInViewFilter</filter-name> <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class> </filter>
决定还是按照规矩来,不要把service层的类直接当任务类去调用,而是改用任务类为action,哇咔咔咔,竟然成功了,可以使用getCurrentSession来获取session了,真的是折磨.....
所以写代码还是要多多试试,多多实践下,然后在试的过程中一不小心就会给你大大的惊喜!!!
虽然记录的很简单,但是总比不记录的要好,恩就这样安慰自己,这个样子也是很好的............................
补充一下一个获取sessionFactory的方式:
WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext(); SessionFactory factory=wac.getBean(SessionFactory.class); Session session=factory.openSession();
在遇到问题的过程中也查阅了很多资料,https://blog.csdn.net/davaid_lee/article/details/44588577