您现在的位置是:首页 >技术杂谈 >关于用quartz手动创建job时,如何将job交给spring管理网站首页技术杂谈

关于用quartz手动创建job时,如何将job交给spring管理

ccddsdsdfsdf 2024-06-16 00:01:02
简介关于用quartz手动创建job时,如何将job交给spring管理

一、前言

最近盘点一些老项目,在没有用一些分布式任务框架前,一般用quartz来实现定时任务,如果想让定时任务corn表达式可修改,那么必定会动态的从数据库中读取corn表达式,并动态修改。

1、通过quartz手动创建一个任务

@Slf4j
@Component
public class SchedulerMain {
   	private Scheduler scheduler;
   public void init() throws SchedulerException {
		scheduler =   StdSchedulerFactory.getDefaultScheduler();
	}
	//设置开始运行方法
	@PostConstruct
	public void start() {
	  //初始化Scheduler 
	   init();
	   //创建一个任务,指定任务类是MainJob
	   JobDetail jobDetail = new JobDetail("MainJob", "main", MainJob.class);
	   Trigger trigger = new CronTrigger(jobDetail.getFullName() + "-Trigger", "main", "0 0 0 * * ?");
 		jobDetail.getJobDataMap().put("schedulerService", schedulerService);
	    scheduler.scheduleJob(jobDetail, trigger);
	    scheduler.start();
	}
	// 关闭定时任务
	@PreDestroy
	public void shutdown() {
		try {
			if (scheduler != null) {
				scheduler.shutdown();
			}
		} catch (Exception e) {
		}
	}
}

一般手动创建一个任务就是上面过程。
看下Main的具体实现:

@Slf4j
public class MainJob implements StatefulJob {

	@Override
	public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
		try {
			SchedulerService schedulerService = (SchedulerService) jobExecutionContext.getJobDetail().getJobDataMap().get("schedulerService");
			schedulerService.execute(false);
		} catch (Exception e) {
		}
	}
}

2、发现问题

看到上面我们创建的MainJob 没,这个对象没有交给spring管理,如果要往这个对象中注入对象,只能在创建这个Job的时候 通过jobDataMap放入。

SchedulerMain 对象中,这个对象是spring管理的,所以可以通过autoWrie注入属性,而job注入属性通过jobDataMap

jobDetail.getJobDataMap().put("schedulerService", schedulerService);

在使用的时候,再从jobDataMap中获取,然后调用相应的方法。这个是不是很麻烦

3、如何将我们创建的Job交给spring创建

Quartz提供了JobFactory接口,让我们可以自定义实现创建Job的逻辑。

public interface JobFactory {
    Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException;
}

这里我们用org.springframework.scheduling.quartz.SchedulerFactoryBean
注意SchedulerFactoryBean实现了FactoryBean,所以注入它时,返回是getObject方法返回的对象

@Override
public Scheduler getObject() {
    //返回scheduler,scheduler是在afterPropertiesSet方法中实例化的
	return this.scheduler;
}

@Override
public void afterPropertiesSet() throws Exception {
  try {
       this.scheduler = createScheduler(schedulerFactory, this.schedulerName);
		//注意这一行代码,初始化AdaptableJobFactory
		this.jobFactory = new AdaptableJobFactory();	
	}
}

如果我们不指定jobFactory,那么Spring就使用AdaptableJobFactory

public class AdaptableJobFactory implements JobFactory {

	@Override
	public Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException {
		try {
			Object jobObject = createJobInstance(bundle);
			return adaptJob(jobObject);
		}
		catch (Exception ex) {
			throw new SchedulerException("Job instantiation failed", ex);
		}
	}


	protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
	    //这里直接通过创建的对象,属性没有注入
		return bundle.getJobDetail().getJobClass().newInstance();
	}

	protected Job adaptJob(Object jobObject) throws Exception {
		if (jobObject instanceof Job) {
			return (Job) jobObject;
		}
		else if (jobObject instanceof Runnable) {
			return new DelegatingJob((Runnable) jobObject);
		}
		else {
			throw new IllegalArgumentException("Unable to execute job class [" + jobObject.getClass().getName() +
					"]: only [org.quartz.Job] and [java.lang.Runnable] supported.");
		}
	}

}

3.1、再创建一个类重写AdaptableJobFactory的newJob方法,实现Job中属性自动注入

也可直接继承SpringBeanJobFactory 这个类是AdaptableJobFactory子类,重写createJobInstance方法

@Component
public class QuartzJobFactory extends SpringBeanJobFactory {

    @Autowired
    private AutowireCapableBeanFactory beanFactory;

    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {

        Object jobInstance = super.createJobInstance(bundle);
        //主动注入属性
        beanFactory.autowireBean(jobInstance);

        return jobInstance;
    }
}

3.2、注入scheduler并将QuartzJobFactory 注入到Scheduler 中

  /**
 * 注入scheduler到spring,schedulerFactory这个对象返回getObject方法创建的对象
 */
<bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
		<property name="jobFactory" ref="jobInstance"/>
		<property name="quartzProperties">
			<props>
				<prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>
				<prop key="org.quartz.threadPool.threadCount">10</prop>
				<prop key="org.quartz.jobStore.misfireThreshold">6000</prop>
			</props>
		</property>
	</bean>

4、自去注入Scheduler 创建任务

@Component
public class QuartzManager {

    @Autowired
    private Scheduler schedulerFactory;
    public void saveJobToSchedule(JobObj obj) throws SchedulerException {
        //任务体
        JobDetail jobDetail = JobBuilder.newJob(obj.getJobObject())
                .withIdentity(obj.getJobName(),obj.getJobGroup()).build();

        // 触发器
        TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
        triggerBuilder.withIdentity(obj.getTriggerName(), obj.getTriggerGroup());
        triggerBuilder.startNow();
        triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(obj.getCornTime()));
        CronTrigger trigger = (CronTrigger) triggerBuilder.build();

        //加入计划
        schedulerFactory.scheduleJob(jobDetail, trigger);
    }
}
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。