Spring quartz定時任務service注入問題


今天想單元測試一下spring中的quartz定時任務,job類的大致結構和下面的SpringQtz1類相似,我的是實現的org.quartz.Job接口,到最后總是發現job類里注入的service為null。一開始還以為spring的配置問題,各種找原因,最后還是確定是沒有注入的原因。

就去網上搜搜吧。也找出來一些眉目。簡單的理解這個原因是job是在quartz中實例化出來的,不受spring的管理。所以就導致注入不進去了。參考這個文章

http://www.tuicool.com/articles/Qjyamu

找着試試的態度,就按照文章里說的。new一個類

public class MyJobFactory extends AdaptableJobFactory {

    //這個對象Spring會幫我們自動注入進來,也屬於Spring技術范疇.
    @Autowired
    private AutowireCapableBeanFactory capableBeanFactory;
    
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        //調用父類的方法
        Object jobInstance = super.createJobInstance(bundle);
        //進行注入,這屬於Spring的技術,不清楚的可以查看Spring的API.
        capableBeanFactory.autowireBean(jobInstance);
        return jobInstance;
    }
}

接下來把他配置到Spring當中去

<bean id="jobFactory" class="com.gary.operation.jobdemo.demo1.MyJobFactory"></bean>

然后在把org.springframework.scheduling.quartz.SchedulerFactoryBean的jobFactory設置成我們自己的。

<bean name="MyScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
  <!-- 其他屬性省略 -->
  <property name="jobFactory" ref="jobFactory"></property>
</bean>

這樣就ok了。

 

問題算是解決了吧,但是想着還要自己寫一個類,還要配置到其它地方,感覺破壞了quartz的完整性,事情不應該是這樣子的。就試着找找其它方法。

 

正好前幾天寫spring和quartz的例子的時候,一個文章介紹了spring下quartz定時任務的兩種方式。博文地址http://kevin19900306.iteye.com/blog/1397744

一個是繼承QuartzJobBean,另一個不用繼承,單純的java類。我想QuartzJobBean是spring里的類,這樣的話這個方式的定時任務類是否就是spring來管理的。注入應該就沒問題了吧。

這是一個很小的項目,實驗起來也很簡單,就啟動,debug。發現還是注入不進去。就接着試第二種方式,debug。驚奇的發現注入沒問題了。

到此為止,這個問題已經解決了。當然還是最后一種方式合理簡單。

 --------------------------------------------------------------------------------------------------------------------------------

Junit的加入

如果再加上Junit的話,情況可能會再復雜一點。有一個現象就是你如果運行了測試方法,就是你可能看不到定時任務運行。在進行任務類里打斷點,也可能不起作用,原因就是junit是另一個單獨的線程,

這個線程結束了,就整個結束了,所以可能就輪不到定時任務運行。junit的這一特點,如果你想測試多線程的代碼,也可能會得到不是你想要的結果。關於怎么測試多線程,請自行百度。

這里有兩個解決方案,第一,像貼出的代碼里一樣,加入這樣的代碼,這個代碼的作用就是防止junit方法的線程退出。

     System.out.println("請輸入信息:");
        Scanner input = new Scanner(System.in);
        int x= input.nextInt();
        System.out.println(x);

第二個方法就是,不加上面的代碼,加入下面的代碼也可能達到定時任務能正常運行的效果。

@Before
    public void before(){
        System.out.println("============啟動前============");
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    }

 

還有junit測試類里增加了一個自己手動寫scheduler調用job的方法,我試了一下,這種方式的service沒法注入。雖然這種方式測試job比較靈活一些。

 

新增加的Junit測試類

import com.dupang.quartz.SpringQtz1;
import org.junit.Before;
import org.junit.Test;
import org.quartz.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;

import java.io.InputStream;
import java.util.Calendar;
import java.util.Scanner;

/**
 * Created by dupang on 2016/11/15.
 */
@ContextConfiguration(locations = { "classpath:applicationContext.xml" })
public class JunitTest extends AbstractJUnit4SpringContextTests {

    @Before
    public void before(){
        //System.out.println("============啟動前============");
        //ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    }
    @Test
    public void helloTest(){
        System.out.println("dupang");
        System.out.println("請輸入信息:");
        Scanner input = new Scanner(System.in);
        int x= input.nextInt();
        System.out.println(x);
    }

    @Test
    public void schedulerTest() throws SchedulerException {
        SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();
        Scheduler sched = schedFact.getScheduler();
        sched.start();

        JobDetail jobDetail = new JobDetail("myJob",Scheduler.DEFAULT_GROUP,SpringQtz1.class);

        SimpleTrigger trigger = new SimpleTrigger("testTrigger", Scheduler.DEFAULT_GROUP);
        trigger.setRepeatCount(10);
        trigger.setRepeatInterval(500);
        trigger.setStartTime(Calendar.getInstance().getTime());

        sched.scheduleJob(jobDetail, trigger);
        System.out.println("請輸入信息:");
        Scanner input = new Scanner(System.in);
        int x= input.nextInt();
        System.out.println(x);
    }
}

 

 

 

貌似不能上傳附件就把所有源碼貼過來吧。

目錄結構為

pom.xml

 

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <packaging>war</packaging>

  <name>test</name>
  <groupId>test</groupId>
  <artifactId>test</artifactId>
  <version>1.0-SNAPSHOT</version>
  <properties>
    <springframework.version>3.0.5.RELEASE</springframework.version>
  </properties>
  <dependencies>


    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${springframework.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context-support</artifactId>
      <version>${springframework.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>${springframework.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>${springframework.version}</version>
    </dependency>

    <dependency>
      <groupId>org.quartz-scheduler</groupId>
      <artifactId>quartz</artifactId>
      <version>1.8.5</version>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>${springframework.version}</version>
    </dependency>
  </dependencies>

</project>

 

 

 

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
         xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
</web-app>
        

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
  <context:component-scan base-package="com.dupang.*" />

  <bean id="jobFactory" class="com.dupang.util.MyJobFactory"></bean>

  <!-- 配置調度程序quartz ,其中配置JobDetail有兩種方式-->
  <!--方式一:使用JobDetailBean,任務類必須實現Job接口 -->
  <bean id="myjob" class="org.springframework.scheduling.quartz.JobDetailBean">
    <property name="name" value="exampleJob"></property>
    <property name="jobClass" value="com.dupang.quartz.SpringQtz1"></property>
    <property name="jobDataAsMap">
    <map>
      <entry key="service"><value>simple is the beat</value></entry>
    </map>
    </property>
  </bean>
  <!--運行時請將方式一注釋掉! -->
  <!-- 方式二:使用MethodInvokingJobDetailFactoryBean,任務類可以不實現Job接口,通過targetMethod指定調用方法-->
  <!-- 定義目標bean和bean中的方法 -->
  <bean id="SpringQtzJob" class="com.dupang.quartz.SpringQtz2"/>
  <bean id="SpringQtzJobMethod" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
    <property name="targetObject">
      <ref bean="SpringQtzJob"/>
    </property>
    <property name="targetMethod">  <!-- 要執行的方法名稱 -->
      <value>execute</value>
    </property>
  </bean>

  <!-- ======================== 調度觸發器 ======================== -->
  <bean id="CronTriggerBean" class="org.springframework.scheduling.quartz.CronTriggerBean">
    <property name="jobDetail" ref="SpringQtzJobMethod"></property>
    <property name="cronExpression" value="0/5 * * * * ?"></property>
  </bean>

  <!-- ======================== 調度工廠 ======================== -->
  <bean id="SpringJobSchedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
      <list>
        <ref bean="CronTriggerBean"/>
      </list>
    </property>
  </bean>

</beans>
MyJobFactory
package com.dupang.util;

import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;

/**
 * Created by dupang on 2016/11/14.
 */
public class MyJobFactory extends AdaptableJobFactory {

    //這個對象Spring會幫我們自動注入進來,也屬於Spring技術范疇.
    @Autowired
    private AutowireCapableBeanFactory capableBeanFactory;

    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        //調用父類的方法
        Object jobInstance = super.createJobInstance(bundle);
        //進行注入,這屬於Spring的技術,不清楚的可以查看Spring的API.
        capableBeanFactory.autowireBean(jobInstance);
        return jobInstance;
    }
}
HelloService
package com.dupang.service;

/**
 * Created by dupang on 2016/11/14.
 */
public interface HelloService {

    void sayHello(String name);
}
HelloServiceImpl
 
        
package com.dupang.impl;

import com.dupang.service.HelloService;
import com.sun.javafx.collections.SourceAdapterChange;
import org.springframework.stereotype.Service;

/**
 * Created by dupang on 2016/11/14.
 */
@Service
public class HelloServiceImpl implements HelloService {
    public void sayHello(String name) {
        System.out.println("Hello to"+ name);
    }
}
 
        
SpringQtz1
package com.dupang.quartz;

import com.dupang.service.HelloService;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

import javax.annotation.Resource;
import java.util.Date;

/**
 * Created by Administrator on 2016/11/9.
 */
public class SpringQtz1 extends QuartzJobBean {

    @Resource
    HelloService helloService;
    private static int counter = 0;
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        helloService.sayHello("dupang");
    }
}
SpringQtz2
package com.dupang.quartz;

import com.dupang.service.HelloService;

import javax.annotation.Resource;
import java.util.Date;

/**
 * Created by Administrator on 2016/11/9.
 */
public class SpringQtz2 {
    private static int counter = 0;
    @Resource
    HelloService helloService;
    protected void execute() {
        helloService.sayHello("dupang");
    }
}

 

最后,我以前也用過quartz的定時任務,當時里面也有service,我都不記得遇到有注入的問題,后來翻了一下代碼,原來就沒有用到注入,它是直接getBean()的方式來獲取service的。如下圖


需要源碼的留言

 

  插播個廣告 


老丈人家的粉皮兒,農產品,沒有亂七八糟的添加劑,歡迎惠顧
 

 

 
        
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM