Spring中使用Quartz调度线程
最近项目中采用spring的quartz调度自动发送邮件业务,应用JobDetailBean实现,在应用过程中发现并发情况下对事务控制做得不够好,看如下代码:
google资料发现spring还有一种方式是MethodInvokingJobDetailFactoryBean,通过这个factroyBean包装Quartz任务,这样就不必继承job类去实现了,看如下:
参考资料:
Spring 为创建Quartz 的 Scheduler,Trigger 和 JobDetail提供了便利的FactoryBean类,以便能够在Spring容器中享受注入的好处。此外Spring还提供了一些便利工具类直接将Spring中的Bean包装成合法的任务。概括来说他提供了两方面的支持:
1. 为Quartz的重要组建类提供更具Bean风格的扩展类;
2. 提供创建Scheduler的BeanFactory类,方便在Spring环境下创建对应的组件对象,并结合Spring容器生命周期进行启动和停止的动作。
让我们来具体研究研究Spring对Quartz的支持,相当好用哦。
创建JobDetail
用户可以直接使用Quartz的JobDetail在Spring中配置一个JobDetail Bean,但是JobDetail使用带参的构造函数,对于习惯通过属性配制的Spring用户来说存在使用上的不便。为此Spring通过扩展JobDetail提供了一个更具Bean风格的JobDetailBean。
JobDetailBean扩展于Quartz的JobDetail。使用该Bean声明JobDetail时,Bean的名字即是任务的名字,如果没有指定所属组,就使用默认组。除了JobDetail中的属性外,还定义了以下属性:
JobClass:类型为Class,实现Job接口的任务。
BeanName:默认为Bean的ID名,通过该属性显式指定Bean名称,它对应任务的名称。
JobDateAsMap:类型为Map,为任务所对应的JobDataMap提供值。之所以需要提供这个属性,是因为用户无法在Spring配置文件为JobDataAsMap类型的属性提供信息,所以Spring通过jobDataAsMap设置JobDataMap的值。
ApplicationContextJobDataKey:用户可以将Spring ApplicationContext的引用保存到JobDataMap中,以便在Job的代码中访问ApplicationContext。为了达到这个目的,用户需要指定一个键,用以在jobDataAsMap中保存 ApplicationContext,如果不设置此键,JobDetailBean就不将ApplicationContext放入到JobDataMap中。
JobListenerNames;类型为String[],指定注册在Scheduler中的JobListeners名称,以便让这些监听器对本任务的事件进行监听。
下面配置片断使用JobDetailBean在Spring中配置一个JobDetail:
jobDetail_1将MyService#doJob()封装成一个任务,同时通过concurrent属性指定任务的类型,默认情况下封装为无状态的任务,如果希望目标封装为有状态的任务,仅需要将concurreng设置成false就可以了。
Spring通过名为concurrent的属性指定任务的类型,能够更直接地描述任务执行的方式(有状态的任务不能并发执行,无状态的任务可并发执行)public class MyService(){ public void doJob(){ System.out.println("doJobing....."); }}
doJob()方法即可以是static,也可以是非static的,但不能拥有方法入参。通过MethodInvokingJobDetailFactoryBean产生的JobDetail不能被序列化,所以不能不持久化到数据库中,如果希望使用持久化任务,用户只能创建正规的Quartz的Job实现了。