我自己的解决过程:http://blog.youkuaiyun.com/axela30w/article/details/67632242(跟下面两种稍微不一样)
第一种解决方案:
一般情况下,quartz的job中使用autowired注解注入的对象为空,这时候我们就要使用spring-quartz提供的AdaptableJobFactory类。
自定义一个类:
[java] view plain copy
- public class 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;
- }
- }
然后在spring中配置:
[html] view plain copy
- <!-- 定时任务的factorybean,配置其他config -->
- <bean id="jobFactory" class="com.xx.job.JobFactory"></bean>
- <bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
- <property name="jobFactory" ref="jobFactory"></property>
- </bean>
这时候,我们在定义类继承job的时候,就可以使用autowired注入service对象了:
[java] view plain copy
- public class Test1Job implements Job {
- public final Logger log = Logger.getLogger(this.getClass());
- @Autowired
- private JobTaskService jobTaskService;
- public void 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的管理。所以就导致注入不进去了。参考这个文章
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的。如下图