Marco's Java【Spring进阶(二) 之 Spring定时任务及Quartz】

前言

在这个竞争异常激烈的社会,每个人或多或少都有着不一样的"病",就拿我来说吧,我有严重的强迫症,东西没有摆放整齐,门要锁好几遍,定闹钟要确认好几遍才能入睡等等,随着年龄的增长,记忆力也衰退了,记不住事儿。
但是老是记不住事儿也不是个办法啊,就像上班打卡,日常工作安排,都是不能忘记的,所以我把Iphone上的"提醒事项这个功能",闹钟呢也设定的"就寝"功能,第一个是用于日常要记住的东西,当我设定时间和任务之后,它会在指定的时间提醒我,再者呢"就寝"会分析我的作息,并给我安排一个合理的作息时间,每天都会重复在指定时间闹醒我,省了不少事儿~

那这些功能统称为我们的定时任务!

何为Quartz

如果我们想在Spring中使用定时任务管理,就不得不提到Quartz了,那什么是Quartz呢?大家先看看它的介绍

Quartz简介:
在企业应用中,我们经常会碰到时间任务调度的需求,比如每天凌晨生成前天报表,每小时生成一次汇总数据等等。Quartz是出了名的任务调度框架,它可以与J2SE和J2EE应用程序相结合,功能灰常强大,轻轻松松就能与Spring集成,使用方便。

Quartz中的概念:  
Quartz有三个核心概念:调度器任务触发器。三者关系简单来说就是,调度器负责调度各个任务,到了某个时刻或者过了一定时间,触发器触动了,特定任务便启动执行。概念相对应的类和接口有:
JobDetail(任务):望文生义就是描述任务的相关情况;
Trigger(触发器):描述出发Job执行的时间触发规则。有SimpleTrigger和CronTrigger两个子类代表两种方式,一种是每隔多少分钟小时执行,则用SimpleTrigger;另一种是日历相关的重复时间间隔,如每天凌晨,每周星期一运行的话,通过Cron表达式便可定义出复杂的调度方案。
Scheduler(调度器):代表一个Quartz的独立运行容器,Trigger和JobDetail要注册到Scheduler中才会生效,也就是让调度器知道有哪些触发器和任务,才能进行按规则进行调度任务。

听到时间的任务和触发,是不是感觉很像JavaScript的Interval事件触发?只不过我们这里我们是在Java中设置定时和触发。Quartz翻译过来就是石英的意思,根据常识,大多数的表都是含有石英成分的,因此Quartz有着时间的含义,那么介绍完Quartz,我们来看看Spring如何启用定时任务吧~

Spring启用Quartz实现定时任务

方式一:基于MethodInvokeJobDetailFactoryBean实现
注意啦,Spring中是没有Quartz jar包的,因此我们需要自己去下载quartz的官方jar包,那么除了之前我们导入过的jar包,我们还需要导入以下三个jar,quartz-2.3.0.jar是使用Quartz的核心jar包,另外两个slf4j和log4j类似,只不过Quartz依赖的是slf4j,因此我们也需要导入,这两个jar可以在mybatis的辅助包中找到。
在这里插入图片描述
那么jar包导入之后,还是给大家看看目录结构啦
在这里插入图片描述
第一步我们来创建一个"定时闹钟"

public class JobClock {
	public void execute() {
		System.out.println("叮铃铃~叮铃铃~" + 
		new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
	}
}

那闹钟有了,我们就要设置任务或者说让它每隔多久闹一次啦,设置闹钟的任务当然就要交给我们的xml咯
注意了这里我专门建了一个application-task.xml存放相关的任务,因为今后的项目会越来越大,那么不同的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:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
	<!-- 创建一个闹钟 -->
	<bean id="jobClock" class="com.marco.quartz.JobClock"></bean>
	<!-- 创建一个任务对象 -->
	<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
		<!-- 设置目标对象-->
		<property name="targetObject" ref="jobClock"></property>
		<!-- 设置目标方法-->
		<property name="targetMethod" value="execute"></property>
	</bean>
	<!-- 设置触发器,cronTrigger的意思就是时间触发器的意思 -->
	<bean id="cronTriggerFactoryBean" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
		<!-- 把任务加入触发器中-->
		<property name="jobDetail" ref="jobDetail"></property>
		<!-- 时间表达式,设置每隔5秒触发一次-->
		<property name="cronExpression" value="0/5 * * * * ?"></property>
	</bean>
	
	<!-- 设置事件调度器,注意只有将Trigger和JobDetail注册到调度器中才能按照规则进行调度-->
	<bean id="springJobSchedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
		<property name="triggers">
			<array>
				<ref bean="cronTriggerFactoryBean"/>
			</array>
		</property>
	</bean>
</beans>

接下来将application-task.xml引入到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:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:task="http://www.springframework.org/schema/task"
	xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
	
	<import resource="classpath:application-task.xml"/>
</beans>

那我们来看看运行结果,是不是每隔5秒"闹钟"闹一次呢?
在这里插入图片描述
注意了,当这个任务开启之后是没有办法控制它什么时候停止的,除非删除这个任务!
另外呢,关于corn的表达式,可以直接点击浏览这个地址 corn格式转换器,会帮你自动生成你想要的定时规则哦

方式二:基于JobDetailBean实现
那凡事最少有三种解决方式,那么我们来介绍第二种方式,首先需要修改我们的JobClock,继承QuartzJobBean,并重写父类的方法executeInternal(),看源码我们不难看出QuartzJobBean实现了Job接口,也就是说QuartzJobBean是任务中的一种,专门用于设置时间,并重写了execute方法,而execute实际上又执行的是executeInternal也就是我们重写QuartzJobBean的方法
在这里插入图片描述
那么分析过它的实现原理之后,我们就来重写QuartzJobBean的方法

public class JobClock extends QuartzJobBean{
	@Override
	protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
		System.out.println("叮铃铃~叮铃铃~" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
	}
}

JobClock继承了QuartzJobBean之后,在application-task.xml中就不用再单独声明
<bean id="jobClock" class="com.marco.quartz.JobClock"></bean>了,我们可以将下面的代码

<bean id="jobClock" class="com.marco.quartz.JobClock"></bean>
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
	<property name="targetObject" ref="jobClock"></property>
	<property name="targetMethod" value="execute"></property>
</bean>

替换为下面的代码,就可以执行我们的任务啦~

<bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
	<!-- 执行目标job的class地址 -->
	<property name="jobClass" value="com.marco.quartz.JobClock" ></property>
	<!-- 设置是否重复执行-->
	<property name="durability" value="true"></property>
</bean>

方式三:基于注解实现
第三种方式永远都是最简单的,果然注解也没有让我们失望,毕竟从难到易才能凸显它的优势嘛
application-task.xml我们就不要了,重点修改JobClock的代码

@Component//通过IoC注入对象JobClock并放置在容器中
public class JobClock {
	@Scheduled(cron="0/5 * * * * ?")
	public void execute() {
		System.out.println("叮铃铃~叮铃铃~" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
	}
}

接下来在applicationContext.xml中对com.marco.quartz下面的类进行扫描就可以啦~

<?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:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:task="http://www.springframework.org/schema/task"
	xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
	<!-- 扫描com.marco.quartz -->
	<context:component-scan base-package="com.marco.quartz"></context:component-scan>
</beans

运行一下… 欸?发现好像,没有生效…
咳,不是故意坑你们,加深一下印象,如果想让task生效有两种方式

第一种方式:
在applicationContext.xml文件中加上下面的标签

<task:annotation-driven/>

这个标签是什么意思呢?根据字面意思annotation-driven就是注解驱动,那么前面加上task,那么它的意思就是任务的注解驱动,@Scheduled(cron="0/5 * * * * ?")就是属于我们任务范畴的,因此只有开启任务注解驱动之后,我们的@Scheduled才会生效

第二种方式:
在JobClock类上注明@EnableScheduling,那么Spring在扫描这个类的时候,就会默认开启驱动,那么调度器也会生效。

@Component
@EnableScheduling
public class JobClock {
	@Scheduled(cron="0/5 * * * * ?")
	public void execute() {
		System.out.println("叮铃铃~叮铃铃~" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
	}
}
后语

有的时候不得不感叹人有的时候真的不如机器呀!随着年龄越来越大,记性也会越来越差,可能有一天写着写着我都会忘了前面讲的到底是啥,所以我会更加认真的写博文,不仅大家能够学到东西,可能在未来的某一天,看到这些文章,也能很快回忆起来,或许还会有些感悟吧~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值