今天想單元測試一下spring中的quartz定時任務,job類的大體結構和下面的SpringQtz1類類似,個人是實現的org.quartz.Job接口,到最後老是發現job類裏注入的service爲null。一開始還覺得spring的配置問題,各類找緣由,最後仍是肯定是沒有注入的緣由。java
就去網上搜搜吧。也找出來一些眉目。簡單的理解這個緣由是job是在quartz中實例化出來的,不受spring的管理。因此就致使注入不進去了。參考這個文章web
http://www.tuicool.com/articles/Qjyamuspring
找着試試的態度,就按照文章裏說的。new一個類apache
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; } }
<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了。app
問題算是解決了吧,可是想着還要本身寫一個類,還要配置到其它地方,感受破壞了quartz的完整性,事情不該該是這樣子的。就試着找找其它方法。maven
正好前幾天寫spring和quartz的例子的時候,一個文章介紹了spring下quartz定時任務的兩種方式。博文地址http://kevin19900306.iteye.com/blog/1397744單元測試
一個是繼承QuartzJobBean,另外一個不用繼承,單純的java類。我想QuartzJobBean是spring裏的類,這樣的話這個方式的定時任務類是否就是spring來管理的。注入應該就沒問題了吧。測試
這是一個很小的項目,實驗起來也很簡單,就啓動,debug。發現仍是注入不進去。就接着試第二種方式,debug。驚奇的發現注入沒問題了。ui
到此爲止,這個問題已經解決了。固然仍是最後一種方式合理簡單。
--------------------------------------------------------------------------------------------------------------------------------
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的。以下圖
須要源碼的留言
插播個廣告
老丈人家的粉皮兒,農產品,沒有亂七八糟的添加劑,歡迎惠顧