- 浏览: 278495 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
u011563440:
u011563440 写道用反射A.class.toGener ...
Java接口中的内部接口和接口中的内部类 -
u011563440:
用反射A.class.toGenericString()--- ...
Java接口中的内部接口和接口中的内部类 -
narutolby:
因为接口本身不能实例化,所以在new 一个 接口的内部类时默认 ...
Java接口中的内部接口和接口中的内部类 -
hekuilove:
请问楼主,第四部如何做?在eclipse哪个位置?
eclipse中使用maven插件的问题:Updating index central|http://repo1.maven.org/maven2 -
小小生:
请问下,如果修改了数据库里面的订单任务的时间,那么不是要重启? ...
利用Spring动态对Quartz定时任务管理
在开发时我们会常常遇到定时任务可以由客户进行管理在什么时候去执行或者甚至不再执行该定时任务。而Spring中所提供的定时任务组件却只能够通过修改trigger的配置才能够控制定时的时间以及是否启用定时任务,为此我搜索了网上的一些解决方法,发现还是不能够很好的解决这个问题。所以干脆仔仔细细的研究了一把Quartz和Spring中相关的源码,我们发现当我们在Spring通过如下声明定时任务时:
<bean id="yourJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="yourJobBean"/> <property name="targetMethod" value="yourJobMethod"/> <property name="concurrent" value="false"/> </bean> <bean id="yourCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean" > <property name="jobDetail" ref="yourobDetail"/> <property name="cronExpression"> <value>0 0 2 * * ?</value> </property> </bean> <bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref local="yourCronTrigger"/> </list> </property> </bean>
所生成的Quartz的JobDetail并不是你定义的Bean,因为JobDetail并不能够直接存放一个实例,具体可以参考JobDetail的构造函数:
JobDetail(String name, String group, Class jobClass) Create a JobDetail with the given name, group and class, and the default settings of all the other properties.
Spring将其转换为MethodInvokingJob或者StatefulMethodInvokingJob类型,其实这两个类都是从QuartzJobBean类继承而来,那么我们来看看QuartzJobBean类的代码:
public abstract class QuartzJobBean implements Job { /** * This implementation applies the passed-in job data map as bean property * values, and delegates to <code>executeInternal</code> afterwards. * @see #executeInternal */ public final void execute(JobExecutionContext context) throws JobExecutionException { try { BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); MutablePropertyValues pvs = new MutablePropertyValues(); pvs.addPropertyValues(context.getScheduler().getContext()); pvs.addPropertyValues(context.getMergedJobDataMap()); bw.setPropertyValues(pvs, true); } catch (SchedulerException ex) { throw new JobExecutionException(ex); } executeInternal(context); } /** * 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. * @see #execute */ protected abstract void executeInternal(JobExecutionContext context) throws JobExecutionException; }
看到这个你或许已经明白了Spring对Quartz的封装原理了。是的,Spring通过这种方式最后就可以在Job真正执行的时候可以反调用到我们所注入的类和方法,具体的代码在MethodInvokingJobDetailFactoryBean类中,如下:
public void afterPropertiesSet() throws ClassNotFoundException, NoSuchMethodException { prepare(); // Use specific name if given, else fall back to bean name. String name = (this.name != null ? this.name : this.beanName); // Consider the concurrent flag to choose between stateful and stateless job. Class jobClass = (this.concurrent ? (Class) MethodInvokingJob.class : StatefulMethodInvokingJob.class); // Build JobDetail instance. this.jobDetail = new JobDetail(name, this.group, jobClass); this.jobDetail.getJobDataMap().put("methodInvoker", this); this.jobDetail.setVolatility(true); this.jobDetail.setDurability(true); // Register job listener names. if (this.jobListenerNames != null) { for (int i = 0; i < this.jobListenerNames.length; i++) { this.jobDetail.addJobListener(this.jobListenerNames[i]); } } postProcessJobDetail(this.jobDetail); }
其实主要是这句:
this.jobDetail.getJobDataMap().put("methodInvoker", this);
这样在调用的时候那就可以调用到我们所注入的类和方法了。
那好我们理解了Spring的原理后就可以动手修改成我们自己的了,所以在设计的时候我们考虑到以下两个方面:
- 精简Spring的配置,添加一个定时任务至少有10几行配置代码,太麻烦了,最好只声明一个Bean就可以了;
- 客户不但能够控制执行的时间,还可以能够启用/禁用某个定时任务。
在上面的思路下,我们决定保留Spring的这个配置:
<bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> </bean>
只不过不需要注入trigger这个属性了,我们仅仅利用Spring来帮我们构造一个Scheduler。
为了简化后续的处理,我们决定定义一个自己Job的接口,方便进行控制及精简代码。
public interface MyJob { /** * 执行具体的任务处理 * @throws JobException */ public void execute() throws JobException; }
接下来我们还是需要一个类似QuartzJobBean类,因此参考Spring的更改如下:
public class QuartzJobBean implements Job { public void execute(JobExecutionContext context) throws JobExecutionException { String targetBeanId = (String)context.getMergedJobDataMap().get("targetObjectId"); if(StringUtils.isNullString(targetBeanId)) return; Object targetBean = SpringUtils.getBean(targetBeanId); if(null == targetBean) return; // 判断是否是实现了MyJob接口 if(!(targetBean instanceof MyJob)) return; // 执行相应的任务 ((MyJob)targetBean).execute(); } }
这个类处理逻辑就是通过获取我在创建JobDetail任务是设定的目标任务Bean的,即targetObjectId的值,然后通过SpringUtils获取该Bean,最后转换成MyJob接口执行。
如何创建JobDetail呢,因为我们前面已经说明不需要在Spring配置那么麻烦而且客户还可以进行配置,因此我们将任务的定时信息存放在数据库中,相应的Domain定义如下:
public class SchedulingJob extends Entry { public static final int JS_ENABLED = 0; // 任务启用状态 public static final int JS_DISABLED = 1; // 任务禁用状态 public static final int JS_DELETE = 2; // 任务已删除状态 private String jobId; // 任务的Id,一般为所定义Bean的ID private String jobName; // 任务的描述 private String jobGroup; // 任务所属组的名称 private int jobStatus; // 任务的状态,0:启用;1:禁用;2:已删除 private String cronExpression; // 定时任务运行时间表达式 private String memos; // 任务描述 // 省略getter和setter... ... public String getTriggerName(){ return this.getJobId() + "Trigger"; } }
这时候我们就可以对定时任务进行控制了,具体控制代码如下:
/** * 启用指定的定时任务 * @param context * @param schedulingJob */ protected void enabled(Context context, SchedulingJob schedulingJob) { try { CronTrigger trigger = (CronTrigger)this.scheduler.getTrigger(schedulingJob.getTriggerName(), schedulingJob.getJobGroup()); if (null == trigger) { // Trigger不存在,那么创建一个 JobDetail jobDetail = new JobDetail(schedulingJob.getJobId(), schedulingJob.getJobGroup(), QuartzJobBean.class); jobDetail.getJobDataMap().put("targetObjectId", schedulingJob.getJobId()); trigger = new CronTrigger(schedulingJob.getTriggerName(), schedulingJob.getJobGroup(), schedulingJob.getCronExpression()); this.scheduler.scheduleJob(jobDetail, trigger); }else{ // Trigger已存在,那么更新相应的定时设置 trigger.setCronExpression(schedulingJob.getCronExpression()); this.scheduler.rescheduleJob(trigger.getName(), trigger.getGroup(), trigger); } } catch (SchedulerException e) { e.printStackTrace(); // TODO } catch (ParseException e) { e.printStackTrace(); // TODO } } /** * 禁用指定的定时任务 * @param context * @param schedulingJob */ protected void disabled(Context context, SchedulingJob schedulingJob) { try { Trigger trigger = this.scheduler.getTrigger(schedulingJob.getTriggerName(), schedulingJob.getJobGroup()); if (null != trigger) { this.scheduler.deleteJob(schedulingJob.getJobId(), schedulingJob.getJobGroup()); } } catch (SchedulerException e) { e.printStackTrace(); // TODO } }
再加上前台处理页面(这个俺就不写了,估计大家都会) 这样我们就可以在控制定时任务的定时时间及启用和禁用了。
最后我们的配置代码如下:
<bean id="taskScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"/> <bean id="tempDirClearTask" class="com.my.module.attachment.util.TempDirClearTask"/>
P.S.
这个定时任务组件是有局限性的,比如所设置的SchedulingJob.jobID必须是和Spring中定时任务Bean的id一致,否则这个定时任务不会被运行。还有这个现在仅支持CronTrigger。而且也不支持分组,不过你可以通过扩展。
再一个要记得写一个加载类在系统初始化时从数据库的配置中加载所有启用的定时任务哦,不然所有定时任务都不能够运行
发表评论
-
[转]servlet 和filter区别和servlet、filter、interceptor的执行顺序
2013-03-21 00:50 19251)servlet和filter的区别 ... -
struts1,struts2,spring mvc区别
2013-03-21 00:26 1971Struts1和Struts2的区别和对比:Action ... -
spring IOC容器实例化Bean的方式与RequestContextListener应用
2013-02-26 12:10 1102spring IOC容器实例化Bean的方式有: ... -
Spring连接各种数据库数据源
2012-06-11 11:01 12101. Oracle数据库数据源配置 <bean id= ... -
SpringSide代码规范
2010-11-09 15:59 1860前言 本文档反映的是SpringSide 团队的编码 ... -
spring 事务
2010-08-24 15:58 1380事务传播属性 Propag ... -
spring注解
2010-06-01 16:26 1200一. spring注解 1.准备工作(1)导入common ... -
Spring 2.5新特性-第二部分-Spring MVC中的新特性
2010-06-01 16:20 1205Spring 框架从创建伊始就 ... -
Spring+JPA工程
2010-05-20 14:32 1768JPA需要的jarhibernate-distribution ... -
生成Excel 和PDF报表
2010-05-20 12:04 2348HTML页面并不总是向用户显示数据输出的最好方式,有时候需要生 ... -
Quartz与Spring结合时如何动态更新Job的启动时间
2010-05-13 23:37 2258转:http://www.blogjava.net/fastz ... -
Quartz在Spring中动态设置cronExpression (spring设置动态定时任务)
2010-05-12 15:42 1365什么是动态定时任务:是由客户制定生成的,服务端只知道该去执行什 ... -
对quartz的总结
2010-05-10 17:21 1656转:http://www.iteye.com/topic/11 ...
相关推荐
利用quartz动态操作定时任务,所有配置信息扔到数据库合理管理,同时把运行日志自动添加数据库表中。
1、spring 定时任务demo ...9、spring+quartz动态定时任务创建 +mybatis(包含quartz动态定时任务的) 10、C#实现的自定义定时任务 可定时运行 多任务运行 11、ETL定时任务(数据同步)(没有数据库,仅供参
最近项目中使用了spring+Quartz定时任务、但是项目最近要集群部署、多个APP下如何利用Quartz 协调处理任务。 大家可以思考一下、现在有 A、B、C三个应用同时作为集群服务器对外统一提供服务、每个应用下各有一个...
NULL 博文链接:https://dolphin-ygj.iteye.com/blog/368874
3.自动配置:SpringBoot的自动配置特性利用了Spring对条件化配置的支持,合理地推测应用所需的bean并自动化配置他们。 4.使部署变得简单,SpringBoot内置了三种Servlet容器,Tomcat,Jetty,undertow.我们只需要一个...
spring很好的集成Quartz,它主要是屏蔽了Quartz底层一些配置,使开 发人员可以几乎不受到任何限制就能够利用Quartz进行定时任务的工作
使用quartz定时器实现系统多活,可以实现很多功能,比如集群中的系统多活检测,多设备接入的时候为每个设备创建定时获取数据机制,利用Quartz设计采集系统并实现系统双活机制_在SpringCloud中自己设计系统双活
13.8. Spring对分段文件上传(multipart file upload)的支持 13.8.1. 介绍 13.8.2. 使用MultipartResolver 13.8.3. 在表单中处理分段文件上传 13.9. 使用Spring的表单标签库 13.9.1. 配置标签库 13.9.2. form...
13.8. Spring对分段文件上传(multipart file upload)的支持 13.8.1. 介绍 13.8.2. 使用MultipartResolver 13.8.3. 在表单中处理分段文件上传 13.9. 使用Spring的表单标签库 13.9.1. 配置标签库 13.9.2. form标签 ...
2.4.2. 对Websphere 事务管理的完整支持 2.4.3. JPA 2.4.4. 异步的JMS 2.4.5. JDBC 2.5. Web层 2.5.1. Spring MVC合理的默认值 2.5.2. Portlet 框架 2.5.3. 基于Annotation的控制器 2.5.4. Spring MVC的表单...
13.8. Spring对分段文件上传(multipart file upload)的支持 13.8.1. 介绍 13.8.2. 使用MultipartResolver 13.8.3. 在表单中处理分段文件上传 13.9. 使用Spring的表单标签库 13.9.1. 配置标签库 13.9.2. form...
2.4.2. 对Websphere 事务管理的完整支持 2.4.3. JPA 2.4.4. 异步的JMS 2.4.5. JDBC 2.5. Web层 2.5.1. Spring MVC合理的默认值 2.5.2. Portlet 框架 2.5.3. 基于Annotation的控制器 2.5.4. Spring MVC的表单...
业务模块包括:权限管理,会员管理,角色管理,定时任务管理(调度管理),问答管理,文章管理,共享管理,短信接口管理和邮件系统发送(注册,找回密码,邮件订阅),跨域登录,消息推送,全文检索,前端国际化等等...
定时任务:开启了多端口多线程执行的定时任务可以执行停止并且修改执行时间,同时添加新的定时任务原理利用quartz来进行实现一个定时任务的功能,是一个基础的demo1.使用技术栈:前端:bootstrap,HTML,CSS,...
springboot整合quartz实现数据库单表配置定时任务,利用反射以及依赖注入实现定时任务的调度
- 增加定时任务管理,通过后台设置启动、关闭,执行任务日志 #### 二次开发准备 1. 开发环境要在IDE里装上lombok插件,否则编译器会报错 2. 程序部署建议使用Maven的assembly插件实现自定义打包方式 3. 项目已经接...