您的位置:首页 > 编程语言 > Java开发

spring+quartz整合--解决quartz任务service注入失败

2017-08-14 11:32 706 查看
这几天需要用到定时任务调度,开始准备用timer,后来经过别人介绍与spring集成的quartz,看了下更适合开发,因此转向quartz的学习,特此记录下来。

quartz使用起来及其方便,与spring整合配置,只需要写一个类继承QuartzJobBean,重写其executeInternal(JobExecutionContext arg0)即可,我们只需要将自己的逻辑代码写在该方法即可。一旦你配置好实现类并设定好调度时间,Quartz将密切注意剩余时间。当调度程序确定该是执行作业的时候,Quartz框架将调用你作业类上的executeInternal()方法并执行相应的任务。无需报告任何东西给调度器或调用任何特定的东西。仅仅执行任务和结束任务即可。如果配置你的作业在随后再次被调用,Quartz框架将在恰当的时间再次调用它。

quartz有三个核心概念,调度器、任务和触发器。三者关系简单来说就是,调度器负责调度各个任务,到了某个时刻或者过了一定时间,触发器触动了,特定任务便启动执行。概念相对应的类和接口有:

  1)JobDetail:描述任务的相关情况,包括配置任务执行的类和方法。

  2)Trigger:描述出发Job执行的时间触发规则。有SimpleTrigger和CronTrigger两个子类代表两种方式,一种是每隔多少分钟小时执行,则用SimpleTrigger;另一种是日历相关的重复时间间隔,如每天凌晨,每周星期一运行的话,通过Cron表达式便可定义出复杂的调度方案。

  3)Scheduler:代表一个Quartz的独立运行容器,Trigger和JobDetail要注册到Scheduler中才会生效,也就是让调度器知道有哪些触发器和任务,才能进行按规则进行调度任务。

quartz的配置一般有两种,一种是配置无参数的任务,就是一个普通方法,要求该执行任务的方法必须为无参方法,否则会报错。另一种是配置可传参方法,因为这里我需要给任务传递一些参数,所以采用第二种配置方法。

首先,需要下载quartz和spring对其提供支持的jar包。我这里采用的是quartz-2.2.1.jar,spring-context-support-4.2.4.RELEASE.jar,下载其他版本请注意包版本之间的兼容。

任务类配置:

<!-- 配置Job的bean -->
<bean id="myJob" class="com.wego.task.Syn_Scheduling"/>


JobDetail的配置

<!-- 配置jobDetail -->
<bean id="myJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<!-- 用到的Job实例 -->
<property name="jobClass" value="com.wego.task.Syn_Scheduling"/>
</bean>


Trigger的配置

<!-- 配置触发器Trigger -->
<bean id="myTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="name" value="work_default_name"/>
<property name="group" value="work_default"/>
<property name="jobDetail" ref="myJobDetail"/>
<!--  每天1点10分30执行  30 10 1 * * ?    每五秒执行一次 0/5 * * * * ? -->
<property name="cronExpression" value="0/30 * * * * ?"/>
</bean>


scheduler配置

<!-- 配置scheduler工厂 -->
<bean id="scheduler"  class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers" ref="myTrigger"/>
<!-- 这里配置任务不随spring容器初始化而自动启动 -->
<property name="autoStartup" value="false"/>
</bean>


注意我标红的地方,因为我需要通过前台点击按钮触发任务启动,所以我设置了不随spring初始化而启动,一般情况下默认是随spring初始化自动启动任务的。手动启动任务需要下面:

Resource res = new ClassPathResource("beans.xml");
BeanFactory bf = new XmlBeanFactory(res);

Scheduler scheduler=(Scheduler)bf.getBean("scheduler");
try {
scheduler.start();//启动任务
} catch (SchedulerException e) {
e.printStackTrace();
}


任务类:

public class Syn_Scheduling extends QuartzJobBean{

@Override
protected void executeInternal(JobExecutionContext arg0)
throws JobExecutionException {

}
}


完整的配置文件

<!-- quartz配置 -->
<!-- 配置Job的bean --><!-- com.wego.action.IndexAction -->
<bean id="myJob" class="com.wego.task.Syn_Scheduling"/>
<!-- 配置jobDetail --> <bean id="myJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <!-- 用到的Job实例 --> <property name="jobClass" value="com.wego.task.Syn_Scheduling"/> </bean>
<!-- 配置触发器Trigger -->
<bean id="myTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="name" value="work_default_name"/>
<property name="group" value="work_default"/>
<property name="jobDetail" ref="myJobDetail"/>
<!-- 每天1点10分30执行 30 10 1 * * ? 每五秒执行一次0/5 * * * * ? -->
<property name="cronExpression" value="0/30 * * * * ?"/>
</bean>
<!-- 配置scheduler工厂 --> <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers" ref="myTrigger"/> <!-- 这里配置任务不随spring容器初始化而自动启动 --> <property name="autoStartup" value="false"/> </bean>


好了,简单配置大概就是这个样子,关于quartz更复杂的配置请参考其官方文档。这里说下我遇到的问题,我需要在一个action中进行任务的调度,但是在任务类中直接加注解注入service报空指针。后来网上查才知道spring是将bean放在ApplicationContext中的。而quartz初始化是自己的JobContext,不同于Spring的ApplicationContext,所以无法直接注入。但我们可以采用SchedulerContext来进行传参,它类似一个map。我们可以先将service注入action,并放入SchedulerContext中,在任务执行类中就可以取到相应的service了。代码如下:

action:

@Controller
@Scope("prototype")
public class IndexAction extends ActionSupport {
Resource(name = "organizeService")
private OrganizationService organizationService;

public void doTask(){
Resource res = new ClassPathResource("applicationContext.xml");
BeanFactory bf = new XmlBeanFactory(res);
Scheduler scheduler = (Scheduler) bf.getBean("scheduler");
try {
// 放入service对象
scheduler.getContext().put("organizationService",organizationService);
scheduler.start();
}catch (SchedulerException e){
e.printStackTrace();
}
}
}


任务类:

public class Syn_Scheduling extends QuartzJobBean{
private OrganizationService organizationService;

@Override
protected void executeInternal(JobExecutionContext arg0)throws JobExecutionException {
try {
organizationService= (OrganizationService) arg0.getScheduler().getContext().get("organizationService");
} catch (SchedulerException e1) {

e1.printStackTrace();
}
}
}


这样就能解决任务注入失败的问题了,其实网上还有很多其他解决办法,有的使用JobDataMap,有的直接将参数写在配置文件中,有时间一定还要琢磨琢磨,知道得多才能找到更合适的方法,解决问题才能更加高效
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring quartz 定时任务