spring定时器

最近正在做一个月报告自动发布的项目,要求根据客户端的设置动态修改定时时间,如客户可以设置 每个月的2号10点自动生成月报告,就用到了spring定时器+quartz。在此感谢http://blog.sina.com.cn/s/blog_49742bac0101fg67.html以及https://blog.csdn.net/gy40235/article/details/41085601和https://www.cnblogs.com/huaxingtianxia/p/5931812.html对我写这篇文章的支持。

用到的spring是4,quartz2.2.3

我单独写了一个定时器的配置文件:applicationContext-time.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">

<!-- 被执行类 -->
<bean id="timer" class="com.walkersoft.bigdata.timer.Timer">
<!-- <property name="scheduler" ref="schedulerFactory"></property> -->
</bean>

<!-- 将类注入到job中 -->
<bean id="timeJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="timer"/>
<property name="targetMethod" value="myTast" />
<property name="concurrent" value="false" />
</bean>

<!-- job注入到定时触发器 -->
<bean id="timeTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref ="timeJob" />
<property name="cronExpression">
<value>0 0 10 * * ?</value>
</property>
</bean>

<!-- 总管理类 将触发器注入到任务工程 -->
<bean id="schedulerFactory" lazy-init="true" autowire="no" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list >
<ref bean="timeTrigger"/>
</list>
</property>
</bean>

<!--  动态设置定时时间的类 -->
<bean id="setTimer" class="com.walkersoft.bigdata.timer.setTimer" lazy-init="false" init-method="resetJob">
<property name="scheduler" ref="schedulerFactory"></property>
</bean>
</beans>

简单说明:定时器的配置文件 其实就是把你自定义的定时类:timer类放到job里面。再把job放到触发器trigger里面。然后把触发器放到spring总的任务管理类上,让spring替我们定时开启任务。如果要用到动态设置定时器。则还要实例化一个你动态设置时间的一个bean ,然后让spring总的任务管理类管理你的bean即可。

可以用注解进行设置,但是注解好像不能支持动态设置定时(这个还没研究),所以用的是配置文件

//执行任务的类

package com.walkersoft.bigdata.timer;

public class Timer {

public void myTast() throws IOException {
System.out.println("任务开始了");

doSomething()//这个是要执行任务的业务逻辑

}

//动态获取定时时间类

package com.walkersoft.bigdata.timer;

public class setTimer {

private org.quartz.Scheduler scheduler;

// 设值注入,通过setter方法传入被调用者的实例scheduler
public void setScheduler(org.quartz.Scheduler scheduler) {
this.scheduler = scheduler;
}


public void resetJob() {

String cronExpression = “从数据库里面获取前台设置的定时任务执行时间”;
TriggerKey triggerKey = TriggerKey.triggerKey("timeTrigger", TriggerKey.DEFAULT_GROUP);
try {
org.quartz.CronTrigger trigger =(org.quartz.CronTrigger)scheduler.getTrigger(triggerKey);
String originConExpression = trigger.getCronExpression(); //获取配置文件默认的设置时间
if(!originConExpression.equals(cronExpression)) { //如果两者时间一样,不用处理,还按照配置文件的时间,如果不一样则把新的时间更新要配置文件上。

//spring定时器启动时会先获取这个地方的时间

CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
//按新的表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
.withSchedule(scheduleBuilder).build();
//按新的trigger设置job
scheduler.rescheduleJob(triggerKey, trigger);
System.out.println( new Date() );
}

} catch (SchedulerException e) {
e.printStackTrace();
}
}
}

设置后就可以了。但是我放到服务器上后,定时器每次执行任务的时候,发现每次都实例化2次,这不是我想到的结果。于是考虑到同步锁。但是还是走不通。加上同步之后还是实例化2次。最后上网查,发现大部分网友都是修改tomcat的配置文件的server.xml文件。修改之后发现果然好了。但是这样做的话,如果项目几年之后更新到新的tomcat上运维工程师只记得把项目放到新的tomcat上,忘了也要修改tomcat的配置文件,这个问题还是会暴露出来啊。暂时还没有解决办法,希望广大网友能提出新的解决办法。这次就谢谢大家了。下面是我修改的tomcat 下面 conf/server.xml的配置

修改前

<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">

<!-- SingleSignOn valve, share authentication between web applications
Documentation at: /docs/config/valve.html -->
<!--
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
-->

<!-- Access log processes all example.
Documentation at: /docs/config/valve.html
Note: The pattern used is equivalent to using pattern="common" -->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log." suffix=".txt"
pattern="%h %l %u %t &quot;%r&quot; %s %b" />
<Context path="" debug="0" docBase="bigdata" reloadable="true"/>
</Host>

修改后

<Host name="localhost" appBase=""
unpackWARs="true" autoDeploy="true">

<!-- SingleSignOn valve, share authentication between web applications
Documentation at: /docs/config/valve.html -->
<!--
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
-->

<!-- Access log processes all example.
Documentation at: /docs/config/valve.html
Note: The pattern used is equivalent to using pattern="common" -->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log." suffix=".txt"
pattern="%h %l %u %t &quot;%r&quot; %s %b" />
<Context path="" debug="0" docBase="webapps/bigdata" reloadable="true"/>
</Host>

大家可以发现 只是把appBase="webapps"修改为空,然后把 docBase="webapps/bigdata"的路径改为以前的appBase+docBase的路径就可以了

到此,spring定时器任务结束。经过几天的测试,正常。

另外  :客户端设置的是每个月的2号十点执行任务。但我为了以防万一 用的是每天的10点执行。如果月报告有就不执行。如果没有就重新生成。看配置文件的时候要注意到这点哦

定时任务时间格式(copy网上的)

字段 允许值 允许的特殊字符 
秒 0-59 , - * / 
分 0-59 , - * / 
小时 0-23 , - * / 
日期 1-31 , - * ? / L W C 
月份 1-12 或者 JAN-DEC , - * / 
星期 1-7 或者 SUN-SAT , - * ? / L C # 
年(可选) 留空, 1970-2099 , - * / 


0 0 12 * * ?---------------在每天中午12:00触发 
0 15 10 ? * *---------------每天上午10:15 触发 
0 15 10 * * ?---------------每天上午10:15 触发 
0 15 10 * * ? *---------------每天上午10:15 触发 
0 15 10 * * ? 2005---------------在2005年中的每天上午10:15 触发 
0 * 14 * * ?---------------每天在下午2:00至2:59之间每分钟触发一次 
0 0/5 14 * * ?---------------每天在下午2:00至2:59之间每5分钟触发一次 
0 0/5 14,18 * * ?---------------每天在下午2:00至2:59和6:00至6:59之间的每5分钟触发一次 
0 0-5 14 * * ?---------------每天在下午2:00至2:05之间每分钟触发一次 
0 10,44 14 ? 3 WED---------------每三月份的星期三在下午2:00和2:44时触发 
0 15 10 ? * MON-FRI---------------从星期一至星期五的每天上午10:15触发 
0 15 10 15 * ?---------------在每个月的每15天的上午10:15触发 
0 15 10 L * ?---------------在每个月的最后一天的上午10:15触发 
0 15 10 ? * 6L---------------在每个月的最后一个星期五的上午10:15触发 
0 15 10 ? * 6L 2002-2005---------------在2002, 2003, 2004 and 2005年的每个月的最后一个星期五的上午10:15触发 
0 15 10 ? * 6#3---------------在每个月的第三个星期五的上午10:15触发 
0 0 12 1/5 * ?---------------从每月的第一天起每过5天的中午12:00时触发 
0 11 11 11 11 ?---------------在每个11月11日的上午11:11时触发.?

原文地址:https://www.cnblogs.com/xuanbo/p/8853727.html