Spring-quartz定時任務service注入問題
我自己的解決過程:http://blog.csdn.net/axela30w/article/details/67632242(跟下面兩種稍微不一樣)
第一種解決方案:
一般情況下,quartz的job中使用autowired註解注入的物件為空,這時候我們就要使用spring-quartz提供的AdaptableJobFactory類。
自定義一個類:
- publicclass JobFactory extends AdaptableJobFactory {
- @Autowired
-
private AutowireCapableBeanFactory capableBeanFactory;
- @Override
- protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
- //呼叫父類的方法
- Object jobInstance = super.createJobInstance(bundle);
- //進行注入
- capableBeanFactory.autowireBean(jobInstance);
- return jobInstance;
- }
- }
- <!-- 定時任務的factorybean,配置其他config -->
- <beanid="jobFactory"class="com.xx.job.JobFactory"></bean>
- <beanid="schedulerFactoryBean"class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
-
<propertyname="jobFactory"ref="jobFactory"></property>
- </bean>
這時候,我們在定義類繼承job的時候,就可以使用autowired注入service物件了:
- publicclass Test1Job implements Job {
- publicfinal Logger log = Logger.getLogger(this.getClass());
- @Autowired
- private JobTaskService jobTaskService;
- publicvoid execute(JobExecutionContext context) throws JobExecutionException {
- //更新上一次執行時間和下一次計劃執行時間
- Date nextProcessTime = context.getNextFireTime();
- ScheduleJob job = (ScheduleJob) context.getJobDetail().getJobDataMap().get("scheduleJob");
- job.setNextProcessTime(nextProcessTime);
- jobTaskService.updateTaskByJobName(job);
- //業務邏輯
- System.out.println("22222222222222222222:");
- }
- }
今天想單元測試一下spring中的quartz定時任務,job類的大致結構和下面的SpringQtz1類相似,我的是實現的org.quartz.Job介面,到最後總是發現job類裡注入的service為null。一開始還以為spring的配置問題,各種找原因,最後還是確定是沒有注入的原因。
就去網上搜搜吧。也找出來一些眉目。簡單的理解這個原因是job是在quartz中例項化出來的,不受spring的管理。所以就導致注入不進去了。參考這個文章
找著試試的態度,就按照文章裡說的。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的完整性,事情不應該是這樣子的。就試著找找其它方法。
一個是繼承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">