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

   这几天需要用到定时任务调度,开始准备用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,有的直接将参数写在配置文件中,有时间一定还要琢磨琢磨,知道得多才能找到更合适的方法,解决问题才能更加高效

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值