`
mwxx
  • 浏览: 12235 次
  • 性别: Icon_minigender_1
  • 来自: 山东
社区版块
存档分类
最新评论

基于Groovy的动态定时任务

阅读更多

目的:实现动态的定时任务脚本框架(增删改定时脚本无需重启服务)

基础:J2SE、Groovy、cron表达式

首先贴出解析cron表达式的类,本人对自己写的这个类并不满意,如果大神有更好的实现还请告诉我一下。

package com.hdb.schedule.common

/**
 * @author MwXx
 * @version 1.0
 * @date 2014-04-21
 */
class CronExpression {
	private Set<Integer> minuteSet
	private Set<Integer> hourSet
	private Set<Integer> dateSet
	private Set<Integer> monthSet
	private Set<Integer> weekSet
	private Set<Integer> yearSet

	String error
	private crontab
	public CronExpression(crontab){
		this.crontab = crontab
		this.buildExpression(this.crontab)
	}

	private void buildExpression(crontab) throws Exception{
		minuteSet = new HashSet<Integer>()
		hourSet = new HashSet<Integer>()
		dateSet = new HashSet<Integer>()
		monthSet = new HashSet<Integer>()
		weekSet = new HashSet<Integer>()
		yearSet = new HashSet<Integer>()

		try{
			int size = crontab.size()
			6.times {index->
				def val
				if(size > index){
					val = crontab[index].toString().trim()
				}else{
					val = '*'
				}
				val.split(',').each { addToSet(index, it) }
			}
		}catch(Exception e){
		}
	}

	private void addValue(int index,int val){
		switch(index){
			case 0:
				minuteSet.add(val)
				break
			case 1:
				hourSet.add(val)
				break
			case 2:
				dateSet.add(val)
				break
			case 3:
				monthSet.add(val)
				break
			case 4:
				weekSet.add(val)
				break
			case 5:
				yearSet.add(val)
				break
		}
	}

	private void addAllValue(int index,int perSize){
		switch(index){
			case 0:
				for(int i=0;i<60;i+=perSize){
					minuteSet.add(i)
				}
				break
			case 1:
				for(int i=0;i<24;i+=perSize){
					hourSet.add(i)
				}
				break
			case 2:
				for(int i=1;i<=31;i+=perSize){
					dateSet.add(i)
				}
				break
			case 3:
				for(int i=1;i<=12;i+=perSize){
					monthSet.add(i)
				}
				break
			case 4:
				for(int i=0;i<7;i+=perSize){
					weekSet.add(i)
				}
				break
			case 5:
				for(int i=2014;i<=2999;i+=perSize){
					yearSet.add(i)
				}
				break
		}
	}

	private void addToSet(int index,String val) throws Exception{
		if(val == '*'){
			this.addAllValue(index, 1)
			return
		}
		if(val.matches(/\d+/)){
			this.addValue(index, val.toInteger())
			return
		}

		String[] per = val.split('/')
		int perSize = 1
		if(per.size() == 2){
			if(per[1].matches(/\d+/)){
				perSize = per[1].toInteger()
			}else if(per[1]!='*'){
				error = "${crontab}[${index}]"
				throw new Exception(error)
			}
		}

		String[] between = per[0].split('-')
		if(between.size() == 1){
			if(between[0] == '*'){
				this.addAllValue(index, perSize)
			}else if(between[0].matches(/\d+/)){
				this.addValue(index, between[0].toInteger())
			}else{
				error = "${crontab}[${index}]"
				throw new Exception(error)
			}
			return
		}
		if(between.size() != 2 || !between[0].matches(/\d+/) || !between[1].matches(/\d+/)){
			error = "${crontab}[${index}]"
			throw new Exception(error)
		}

		int start = between[0].toInteger()
		int end = between[1].toInteger()
		int max = 0
		int min = 0
		switch(index){
			case 0:
				max = 59
				break
			case 1:
				max = 23
				break
			case 2:
				max = 31
				min = 1
				break
			case 3:
				max = 12
				min = 1
				break
			case 4:
				max = 6
				break
			case 5:
				max = 2999
				min = 2014
				break
		}

		if(end >= start){
			while(start <= end){
				addValue(index, start)
				start += perSize
			}
		}else{
			while(min <= end){
				addValue(index, min)
				min += perSize
			}
			while(start <= max){
				addValue(index, start)
				start += perSize
			}
		}
	}

	boolean valide(Calendar calendar){
		int minute = calendar.get(Calendar.MINUTE)
		if(!minuteSet.contains(minute)){
			return false
		}
		int hour = calendar.get(Calendar.HOUR_OF_DAY)
		if(!hourSet.contains(hour)){
			return false
		}
		int date = calendar.get(Calendar.DATE)
		if(!dateSet.contains(date)){
			return false
		}
		//获取到的月份需要加1,如1月获取到的是0
		int month = calendar.get(Calendar.MONTH) + 1
		if(!monthSet.contains(month)){
			return false
		}
		//获取到的周需要-1 如周五获取到的是6
		int week = calendar.get(Calendar.DAY_OF_WEEK) - 1
		if(!weekSet.contains(week)){
			return false
		}
		int year = calendar.get(Calendar.YEAR)
		if(!yearSet.contains(year)){
			return false
		}
		true
	}
}

 

下面这个类的功能是每间隔1分钟,扫描编译指定文件夹下的Groovy脚本,解析脚本的crontab属性,判断是否执行该脚本。

package com.hdb.schedule

import org.apache.log4j.Logger

import com.hdb.schedule.common.CronExpression
import com.hdb.util.FileUtils

/**
 * @author MwXx
 * @version 1.0
 * @date 2014-04-18 18:46:23
cron 表达式含义
 第1列分钟1~59
 第2列小时0~23
 第3列日1~31
 第4列月1~12
 第5列星期0~6(0表示星期天)
 */
class GroovyTask extends TimerTask{
	private static final String[] rootDirs = ['crontab\\monitor\\', 'crontab\\report\\', 'crontab\\task\\']
	private static Logger log = Logger.getLogger(GroovyTask.class)

	public void run() {
		try {
			Calendar calendar = Calendar.getInstance()
			GroovyScriptEngine engine = new GroovyScriptEngine(rootDirs)
			Binding binding = new Binding();
			binding.setVariable("language", "Groovy");

			rootDirs.each {rootDir->
				try{
					File rootPath = new File(FileUtils.getProjectDir())
					rootPath = new File(rootPath,rootDir)
					rootPath.eachFile {schFile ->
						if(!schFile.isDirectory() && schFile.getName().endsWith('.groovy')){
							def schClass = engine.loadScriptByName(schFile.getName())
							def crontab = schClass.getMetaClass().getProperties().find { it.name == 'crontab' }
							if(crontab){
								CronExpression cronExp = new CronExpression(schClass.getAt('crontab'))
								if(cronExp.error){
									log.error "Task: ${schClass.toString()}'s crontab \"${cronExp.error}\" is not compliance."
								}else if(cronExp.valide(calendar)){
									def info = '\n' + (' -'*50) + "\nTask:${schClass.toString()} will be invoke."
									log.info(info)
									Thread.start {
										schClass.getMetaClass().invokeMethod(schClass.newInstance(), "execute", null)
									}
								}
							}
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args){
		Timer timer = new Timer()
		//每分钟执行一次,动态加载 Groovy 脚本,得到crontab属性,从而决定是否该执行 execute 方法
		timer.schedule(new GroovyTask(), 0, 60000)
	}
}

忘了在后面附上定时任务的例子……现在补上

/**
 * @author MwXx
 * @version 1.0
 * @date 2014-03-28
 */
class TaskDemo{
	
	/** 每个小时的第10分钟执行 */
	static crontab = [10]
	
	void execute(){
		println '我执行啦...'
	}
}

  

定时任务脚本的格式要求:

1.文件名以.groovy结尾

2.类中有static crontab = [] 变量的定义

3.类中有void execute(){}方法的实现

 

crontab属性的用法在GroovyTask类的注释中说明了。再附上几个例子。

/** 每周五0点10分执行 */
static crontab = [10, 0, '*', '*', 5]

/** 每月1号10点执行 */
static crontab = [0, 10, 1]

/** 每个小时的第10分钟执行 */
static crontab = [10]

/** 每天9点执行 */
static crontab = [0, 9]

/** 8点-18点之间每10分钟执行一次 */
static crontab = ['*/10','8-18']

/** 每天8点、13点、17点20分执行 */
static crontab = [20, '8,13,17']

/** 每周一到周五13点、18点执行 */
static crontab = [0,'13,18','*','*','1-5']

 

 

不会Groovy也不用担心,有JAVA基础的话,学习Groovy语言特别容易。

而且只需要在项目中加上Groovy的jar包就能使用Groovy语言的各种特性了。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics