定时任务知多少(一)——Spring实现内存级quartz

开发需求中,我们经常会遇到定时处理的需求,比如说定时提醒用户还款、定时备份数据库、定时去合作公司文件服务器读取数据、产品自动下架、用户所下的订单超时取消……等等等等,从本篇文章开始,我们来一起讨论一下项目中定时任务的应用。


然而我们都知道:是先有业务,再有技术。技术是为业务而生的。所以对于不同的需求,我们需要使用不同的技术,来合理的解决需求的问题。总结一下,通过以下四个技术层面,能够解决几乎所有的定时需求:

1、Spring实现的内存级quartz;

2、JDK中Timer及JDK中其他定时处理类;

3、集成Spring,将quartz持久化到mongodb中;

4、quartz集群。

……


今天,我们来讲第一个,也是最简单的一个。

一、Spring实现的内存级quartz

该定时任务,主要是Spring对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:jee="http://www.springframework.org/schema/jee"
	xmlns:tx="http://www.springframework.org/schema/tx" 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-3.0.xsd
	 http://www.springframework.org/schema/tx
	 http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
	 http://www.springframework.org/schema/jee
	 http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
	 http://www.springframework.org/schema/aop
	 http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
	 http://www.springframework.org/schema/context
	 http://www.springframework.org/schema/context/spring-context-3.0.xsd
	 http://activemq.apache.org/schema/core
	 http://activemq.apache.org/schema/core/activemq-core.xsd"
	default-lazy-init="true">
	
	<!--注入一个bean  -->
	<bean id="testQtz"  class="com.quartz.TestQtz" />
	
	<!--指定定时执行的方法  -->
	<bean id="testQtzJobMethod"
		class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
		<property name="targetObject">
			<ref bean="testQtz" />
		</property>
		<property name="targetMethod">
			<value>executeQtz</value> <!--指定testQtz Bean中,定时执行的方法名称  -->
		</property>
	</bean>

	<!-- ======================== 调度触发器 ======================== -->
	<!-- 设置几点开始周期性 的 执行 -->
	<bean id="testQtzCronTrigger"  class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
   		<property name="jobDetail" ref="testQtzJobMethod" />
		<property name="cronExpression" value="0 01 0 * * ?" />   <!-- 工作日的 00:01分执行 -->
	</bean>
	
	
	<!-- ======================== 调度工厂 ======================== -->
	
	<!-- 调度工厂 -->
	<bean id="SpringJobSchedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
		<property name="triggers">
		     <list>
			     <ref local="testQtzCronTrigger" />
		    </list> 
		</property>
	</bean>
	
</beans>


定时任务将执行的方法类如下:

package com.quartz.testQtz;

public class TestQtz {

	private static int counter = 0;  
    public void executeQtz()  {  
        counter++;  
        System.out.println("第 " + counter +" 次执行");  
    }  
}


这样就可以了,上面的配置加方法,就可以执行定时任务了,很简单吧。

下面我们来大概说一下它的原理。

上面的这种定时任务的实现,还是非常普遍的,因为使用起来非常的简单,只需要一个Spring的简单的配置,即可完成需求。实际上,这是Spring做的一个对Quartz的一个比较完整的实现,所以我们用来起来才没有感觉到Quartz的存在,所以才会觉得很简单。

我们通过上面Spring的配置,通过设置cronExpression,我们可以使要执行的方法周期性的执行。比如每天晚上12点钟,准时备份数据库,比如还差3天用户将逾期时,发送提醒短信等等。我们都可以使用该种方式执行。

尺有所长,寸有所短。尽管上述方法用起来很方便,但是我能够容纳它的缺点,才能够对症下药。

缺点如下:

1、该种方法,是将定时任务序列化到内存当中的。也就是说,当系统重新部署,需要重启服务器时,该定时任务会从内存中清除(几乎是废话,应用服务器都停了,定时任务还怎么能够在内存当中。。),当应用服务器重新启动后,定时任务才会重新载入内存当中。

所以说,这种定时任务,应用服务器停止时间如果比较长的话,则当日此期间未执行的定时任务,就没有机会执行了。

2、执行执行并不是非常准确的(即执行时间不准确)。也就是说定点儿执行的定时任务,到了时间可能仍然没有执行。这是为什么呢?定时任务,说白了,就是一个进程。应用服务器启动时,定时任务进入内存,并进入阻塞状态。这时,我们可以理解为有一个timer不断去扫面执行时间。当到执行时间是,经过内存调度,即将执行的定时任务进入就绪状态,等待CPU进行调度,注意它并不会阻塞其他线程的调度,而是将自己置于就绪状态等待CPU空闲时调度。所以说,如果CPU一直忙碌的话,就会发生定时任务到时间仍未执行的情况。


综合上述这两种缺点,我们就清楚了如何、以及合适使用该种定时任务了。

实际应用中,由于这种定时任务的需求比较特殊,我们经常会将定时任务分离出来,将其作为一个独立的项目,独立部署。因为应用服务器是需要更改的,不断的产品迭代、产品的上线,很可能会重新启动应用服务器,为了不对定时任务造成影响,我们通常会将其分离出来对部署。

由于定时任务,并非准确执行,我们需要容忍它这一点(其实相差时间不会很大)。


本文只是简单介绍了定时任务,非常简单的一种实现,接下来我将会介绍quartz强大的功能,敬请期待。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值