spring quartz配置使用
前期项目使用spring task配置的,由于执行是单线程方式,一个定时任务执行太久会影响下一个定时任务执行,所以改用spring quartz 多个线程并发的方式
前期准备:导入jar包
List quartz = ['org.quartz-scheduler:quartz:2.3.2']
dependencies {
compile lombok, spring, quartz......
testCompile junit, mock
compile ("掩码-adm:2.0.2"){
exclude module: "dom4j"
}
}
List quartz = ['org.quartz-scheduler:quartz:2.3.2']
1.task封装类
public class TaskConfig {
private String jobName;
private String jobGroup;
private String triggerName;
private String triggerGroup;
private String cronExpression;
private Class configClass;
public static TaskConfig newTaskConfig() {
return new TaskConfig();
}
public TaskConfig withJobName(String jobName) {
this.jobName = jobName;
return this;
}
public TaskConfig withJobGroup(String jobGroup) {
this.jobGroup = jobGroup;
return this;
}
public TaskConfig withTriggerName(String triggerName) {
this.triggerName = triggerName;
return this;
}
public TaskConfig withTriggerGroup(String triggerGroup) {
this.triggerGroup = triggerGroup;
return this;
}
public TaskConfig withCronExpression(String cronExpression) {
this.cronExpression = cronExpression;
return this;
}
public TaskConfig withConfigClass(Class configClass) {
this.configClass = configClass;
return this;
}
// ...... get,set
}
2.quartz初始化类,将所有的定时任务注入IOC
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
@Lazy(false)
@Service
public class QuratzTaskService {
@Autowired
private Scheduler scheduler;
@PostConstruct
public int init() {
int count = 0;
try {
List<TaskConfig> list = doLoadTaskConfig();
for (TaskConfig taskConfig : list) {
String jobName = "jobName";
String jobGroup = "jobGroup";
JobDetail jobDetail =
JobBuilder.newJob(taskConfig.getConfigClass()).withIdentity(jobName, jobGroup).build();
// trigger和job共用一套name和group
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup)
.withSchedule(CronScheduleBuilder.cronSchedule(taskConfig.getCronExpression())).forJob(jobName, jobGroup).build();
scheduler.scheduleJob(jobDetail, trigger);
}
scheduler.start();
count = list.size();
} catch (SchedulerException e) {
e.printStackTrace();
}
return count;
}
private List<TaskConfig> doLoadTaskConfig() {
// 可以将定时任务存储到MySQL数据库,拉取列表处理
List<TaskConfig> list = new ArrayList<>();
TaskConfig config = TaskConfig.newTaskConfig()
.withConfigClass(HoldPositionsTask.class)
.withCronExpression("0 */2 * * * ?");
list.add(config);
TaskConfig config1 = TaskConfig.newTaskConfig()
.withConfigClass(HoldAumTask.class)
.withCronExpression("*/20 * * * * ?");
list.add(config1);
return list;
}
}
3.定义定时任务
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.stereotype.Service;
@Service
public class HoldPositionsTask implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("quartzTaskExecute..." + this.getClass().getName() + "定时任务开始执行.....");
// doSomethings...
}
}
跑了一把,IOC容器没有起来。。。。。
报错如下
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'quratzTaskService': Unsatisfied dependency expressed through field 'scheduler'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.quartz.Scheduler' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:643)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:897)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:879)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:551)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:401)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:292)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:103)
at cn.webank.weup.biz.web.listeners.WeupSpringContextLoaderListener.contextInitialized(WeupSpringContextLoaderListener.java:28)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4697)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5163)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1412)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1402)
at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266)
at java.util.concurrent.FutureTask.run(FutureTask.java)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.quartz.Scheduler' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1717)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1273)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1227)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640)
... 26 more
WeupSpringContextLoaderListener.contextInitialized|spring ApplicationContext 启动失败
Disconnected from the target VM, address: '127.0.0.1:59788', transport: 'socket'
Process finished with exit code 1
这个是因为 @Autowired private Scheduler scheduler;实现类没有注入IOC,补充两个类
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
/**
* 结合QuartzConfig,将Quartz的Job交由Spring管理,解决@Autowired变量为空的问题
*
*/
public class QuartzJobFactory extends SpringBeanJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
// 调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
// 进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
import org.quartz.Scheduler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
/**
* 将Scheduler的Bean交由Spring管理
*/
@Configuration
public class QuartzConfig {
@Bean
public Scheduler scheduler(SchedulerFactoryBean schedulerFactoryBean) {
return schedulerFactoryBean.getScheduler();
}
@Bean
public SchedulerFactoryBean schedulerFactoryBean(QuartzJobFactory jobFactory) {
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
schedulerFactoryBean.setJobFactory(jobFactory);
return schedulerFactoryBean;
}
@Bean
public QuartzJobFactory jobFactory() {
return new QuartzJobFactory();
}
}
再次启动项目,报错就没了。部署Linux上定时任务页正常跑起来了
这里的日志是公司内部的一个日志框架打印的。