`
lee1177
  • 浏览: 118570 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

quartz+spring-集群版任务动态载入及修改

阅读更多

    关于单机版的配置描述前文已经提过了,有兴趣的可以看下

http://lee1177.iteye.com/blog/2171379

    这里介绍对于集群做的一个简单实现。

    首先其实quartz针对就群有自己的实现了,本人这个实现不过是简化并在前文基础上做的一个集群实现。

    本实现目的是在集群中任一一台作为运行节点,如果该节点不可用,自动切换为其他节点继续执行。同时自动检测定时任务设定被修改的重新加载。未考虑负载均衡及异常任务恢复情况。

    下面说如何做的:

    首先是SchedulerJob的定义比之前多了一个更新时间的属性

public class SchedulerJob {
	public static final String JOB_GOURP = "JOB_GOURP";	//任务组
	public static final int STATUS_USED = 1;	//可用状态
	
	/** 任务id spring的bean名称*/
    private String jobId;
    /** 任务名称 */
    private String jobName;
    /** 任务状态 0停用 1启用 */
    private Integer jobStatus;
    /** 任务运行时间表达式 */
    private String cronExpression;
    /** 更新时间,用于集群自动动态更新任务修改*/
	private Long updateTime;

 

    对应任务SchedulerJobBean同前文一致;

 

    然后自定义一个集群quartz运行工厂类,来执行定时任务实现

    

/**
 * 集群任务执行工厂
 * @ClassName: ClusterQuartzJobFactory
 */
@DisallowConcurrentExecution
public class ClusterQuartzJobFactory implements Job {
	private static final Logger log = LoggerFactory.getLogger(ClusterQuartzJobFactory.class);
    public void execute(JobExecutionContext context) throws JobExecutionException {
    	SchedulerJob scheduleJob = (SchedulerJob)context.getMergedJobDataMap().get("scheduleJob");
    	if(scheduleJob.getJobId().equals(ClusterQuartzManager.SCHEDULER_CHECK_JOB)
    			||ClusterQuartzManager.isRun()){	//如果是检查任务或该服务正在运行
        	try{
        		SchedulerJobBean jobBean = (SchedulerJobBean) ContextHolder.getBean(scheduleJob.getJobId());
                jobBean.execute(context);
    		} catch (Exception ex){
    			log.error("====================Scheduler-error-begin====================");
    			log.error(ex.toString());
    			StackTraceElement[] element = ex.getStackTrace();
    			for(int i=0;i<element.length;i++){
    				log.error("位置:"+element[i]);
    			}
    	        log.error("====================Scheduler-error-end====================");
    		}
    	}
    }
}

 

 

    然后集群任务管理器

 

/**
 * Quartz集群管理器
 * @Create In 2014年12月31日 By lee
 */
public class ClusterQuartzManager extends AbstractQuartzManager{
	private static final Logger log = LoggerFactory.getLogger(ClusterQuartzManager.class);
	public static final int STATE_RUN = 1;	//运行状态
	public static final int STATE_WAIT = 0;	//等待状态
	public static final String SCHEDULER_CHECK_JOB = "schedulerCheckJob";	//定时检查任务Id
	private static String jobFactoryKey = null;	//每个服务实例一个单独KEY
	private static int jobState = -1;		//该服务实例状态
	/**
	 * 启动所有定时任务
	 * @throws SchedulerException 
	 * @Methods Name startAll
	 * @Create In 2014年9月23日 By lee
	 */
	public static void startAll() throws SchedulerException{
		if(jobFactoryKey==null){
			jobFactoryKey = UUID.randomUUID().toString();
		}
		if(jobState==-1){
			jobState = STATE_WAIT;
		}
		SchedulerServerService schedulerServerService = ContextHolder.getBean(SchedulerServerService.class);
		schedulerServerService.save(new SchedulerServer(jobFactoryKey,jobState,DateUtils.getCurrentDateTime().getTime()));
		create(ClusterQuartzManager.instanceCheckJob());
		log.debug("=====定时任务启动完成=====");
	}


	/**
	 * 构造默认的检查任务
	 * @Methods Name instanceCheckJob
	 * @Create In 2014年12月31日 By lee
	 * @return
	 */
	private static SchedulerJob instanceCheckJob(){
		SchedulerJob checkJob = new SchedulerJob();
		checkJob.setCronExpression("0/5 * * * * ?");	//每5秒运行检查一次
		checkJob.setJobId(SCHEDULER_CHECK_JOB);
		checkJob.setJobStatus(SchedulerJob.STATUS_USED);
		return checkJob;
	}
	/**
	 * 当前是否为运行状态
	 * @Methods Name isRun
	 * @Create In 2014年12月30日 By lee
	 * @return
	 */
	public static boolean isRun(){
		return jobState==STATE_RUN;
	}
	public static String getFactoryKey(){
		return jobFactoryKey;
	}
	/**
	 * 启动
	 * @Methods Name startUp
	 * @Create In 2015年1月4日 By lee
	 * @return	首次启动返回true,如果已启动返回false
	 * @throws SchedulerException
	 */
	public static boolean startUp() {
		if(jobState != STATE_RUN){
			SchedulerJobService schedulerJobService = ContextHolder.getBean(SchedulerJobService.class);
			List<SchedulerJob> jobs = schedulerJobService.findAll();
			for(SchedulerJob job : jobs){
				if(SchedulerJob.STATUS_USED==job.getJobStatus()){
					try {
						create(job);
					} catch (SchedulerException e) {
						e.printStackTrace();
					}
				}
			}
			log.debug("=====定时任务启动完成=====");
			jobState = STATE_RUN;
			return true;
		}
		return false;
	}
	/**
	 * 设置为等待
	 * @Methods Name toWait
	 * @Create In 2015年1月4日 By lee
	 */
	public static void toWait() {
		if(jobState == STATE_RUN){
			SchedulerJobService schedulerJobService = ContextHolder.getBean(SchedulerJobService.class);
			List<SchedulerJob> jobs = schedulerJobService.findAll();
			for(SchedulerJob job : jobs){
				try {
					delete(job);
				} catch (SchedulerException e) {
					e.printStackTrace();
				}
			}
			log.debug("=====定时任务启动完成=====");
			jobState = STATE_WAIT;
		}
	}

}

 

 

   可以看到在管理器启动时默认只启动了一个检查任务,这个实现就是利用这检查任务来实现集群中节点的状态检查及激活更新等动作,检查任务如下

 

/**
 * 定时任务检查任务
 * @ClassName: SchedulerCheckJob
 * @Create In 2014年12月30日 By lee
 */
@Component
@Transactional
public class SchedulerCheckJob implements SchedulerJobBean{
	//private static Log logger = LogFactory.getLog(SchedulerCheckJob.class);
	@Autowired
	private SchedulerServerService schedulerServerService;
	@Autowired
	private SchedulerJobService schedulerJobService;
	@Override
	public void execute(JobExecutionContext context) {
		Long curTime = context.getScheduledFireTime().getTime();
		if(checkRun(curTime)){	//如果当前服务启动
			if(!ClusterQuartzManager.startUp()){	//如果不是首次启动,检查是否有更新
				Long previousTime = null;
				if(context.getPreviousFireTime()!=null){
					previousTime = context.getPreviousFireTime().getTime();
				}else{
					previousTime = curTime+5000;
				}
				checkJobUpdate(previousTime,curTime);
			}
			//logger.info("=====["+QuartzManager.getFactoryKey()+"]=====RUN=====");
		}else{
			ClusterQuartzManager.toWait();
			//logger.info("=====["+QuartzManager.getFactoryKey()+"]=====WAIT=====");
		}
	}
	/**
	 * 检查任务是否有更新
	 * @Methods Name checkJobUpdate
	 * @Create In 2014年12月30日 By lee
	 * @param previousTime
	 * @param curTime
	 */
	private void checkJobUpdate(Long previousTime,Long curTime) {
		List<SchedulerJob> updateJobs = schedulerJobService.findByUpdateTimeBetween(previousTime,curTime);
		for(SchedulerJob job : updateJobs){
			if(SchedulerJob.STATUS_USED==job.getJobStatus()){
				try {
					ClusterQuartzManager.update(job);
				} catch (SchedulerException e) {
					e.printStackTrace();
				}
			}
		}
	}
	/**
	 * 检查当前服务是否用运行服务
	 * @Methods Name checkRun
	 * @Create In 2014年12月30日 By lee
	 * @param curTime
	 * @return
	 */
	private boolean checkRun(Long curTime){
		String curServerKey = ClusterQuartzManager.getFactoryKey();
		List<SchedulerServer> servers = schedulerServerService.findAll();
		SchedulerServer readServer = null;	//备用服务
		SchedulerServer runServer = null;	//运行服务
		SchedulerServer curServer = null;	//当前服务
		boolean runServerError = true;		//运行服务异常
		for(SchedulerServer server : servers){
			if(server.getJobServer().equals(curServerKey)){
				curServer = server;
			}
			Long updateTime = server.getUpdateTime();
			long afterTime = curTime-updateTime;
			//logger.info("=====["+DateUtils.getCurrentDateTimeStr()+"]=====["+curServerKey+"]=====["+afterTime+"]=====");
			if(updateTime!=null&&(afterTime<=5000)){//如果更新时间小于等于5S,说明该服务可用
				if(server.getState()==SchedulerServer.STATE_RUN){
					runServer = server;
					runServerError = false;
				}
				if(readServer==null&&server.getState()==SchedulerServer.STATE_WAIT){
					readServer = server;
				}
			}else{
				if(!server.getJobServer().equals(curServerKey)){
					schedulerServerService.delete(server);
				}
			}
		}
		//如果当前服务未被实例到数据库,放弃本次运行检查
		if(curServer==null){
			curServer = new SchedulerServer(curServerKey,SchedulerServer.STATE_WAIT,curTime);
			schedulerServerService.save(curServer);
			return false;
		}else{
			if(runServerError){	//如果运行服务不可用
				/**
				 * 如果当前服务为备用服务
				 */
				curServer.setUpdateTime(curTime);
				if(readServer!=null&&readServer.getJobServer().equals(curServerKey)){
					if(runServer!=null){
						schedulerServerService.delete(runServer);
					}
					curServer.setState(SchedulerServer.STATE_RUN);
					schedulerServerService.save(curServer);
					return true;
				}else{
					schedulerServerService.save(curServer);
					return false;
				}
			}else{	//如果可用,只更新当前服务状态
				curServer.setUpdateTime(curTime);
				schedulerServerService.save(readServer);
				if(runServer.getJobServer().equals(curServerKey)){
					return true;
				}else{
					return false;
				}
				
			}
		}
	}
}

 另涉及到一个集群节点状态实体如下

public class SchedulerServer {
	private static final long serialVersionUID = 1204654463096914772L;
	public static final int STATE_RUN = 1;
	public static final int STATE_WAIT = 0;
	private String jobServer;	//定时任务服务(集群内每个服务启动一个)
	private Integer state;		//状态
	private Long updateTime;	//更新时间

 springxml配置与前文一致

 

 

   

    主要完成以下几个功能:

  1. 减少quartz配置;
  2. 通过配置文件动态修改quartz是否运行(我的配置文件也是动态的);
  3. 动态修改定时任务的状态预计运行规则;
  4. 实现集群中只有一个节点运行任务;
  5. 实现集群中运行节点异常其他节点自动唤醒运行方式;

 

分享到:
评论
2 楼 zhuyuqu840123 2016-06-29  
能给代码吗?
1 楼 hanyi_ 2016-02-03  

相关推荐

    quartz整合springbatch动态集群定时实现mysql参考

    在这个“quartz_springbatch_dynamic”项目中,我们将看到如何将这两个强大的工具结合起来,以实现动态集群环境中的定时任务执行,并使用MySQL作为数据存储。 Quartz是一个开源的作业调度框架,允许开发者创建、...

    quartz+spring分布式集群

    将Quartz与Spring结合使用,可以方便地在Spring应用程序中进行定时任务的管理。 在“quartz+spring分布式集群”场景下,我们可以实现跨多个节点的作业调度,从而提高系统的可扩展性和可靠性。JDBC-JobStore是Quartz...

    spring3.0+quartz-1.6.0定时

    Spring 3.0 和 Quartz 1.6.0 结合使用是企业级应用中常见的定时任务解决方案。Spring 是一个强大的Java应用程序框架,提供了依赖注入、AOP(面向切面编程)以及众多其他功能,而Quartz则是一个开源的作业调度框架,...

    quartz+spring分布式集群调度

    总结,Quartz+Spring的分布式集群调度方案能够帮助开发者构建稳定且可扩展的定时任务系统。通过合理配置和实践,可以满足复杂的企业级应用需求。而提供的"spring-quartz"示例则为学习和实践这一方案提供了宝贵的参考...

    quartz和spring-quartz

    Quartz和Spring-Quartz是两个在Java世界中广泛使用的定时任务管理框架。Quartz是一个开源的作业调度框架,允许应用程序定义和调度任务在特定时间执行。而Spring-Quartz则是Spring框架对Quartz的集成,它使得在Spring...

    Springboot+Mybatis-plus+ SpringMvc+Shiro+Redis企业级报表后台管理系统

    实现异步处理,定时任务,整合Quartz Job以及Spring Task 邮件管理功能, 整合spring-boot-starter-mail发送邮件等, 数据源:druid 用户管理,菜单管理,角色管理,代码生成 运行环境 jdk8+oracle+redis+...

    Quartz+Spring定时触发器例子

    Quartz和Spring结合使用可以构建强大的定时任务管理系统。Quartz是一个开源的作业调度框架,它允许应用程序定义和调度任务在特定时间执行。而Spring框架则提供了丰富的依赖注入和管理功能,使得集成Quartz变得更加...

    maven父子项目(java)+SSM(spring+springmvc+spring-mybatis)+quartz持久化到Oracle数据库

    本人搭的项目,可以正常运行。用于自己存留备份,若有人需要也可下载。 项目用到的技术点: ...quartz持久化到Oracle数据库+ log4j+ Excel处理(只有工具代码,使用代码没放)+ spring-test(测试例子)+ bootstrap

    spring-cache.xsd+spring-encache.xsd

    "quartz2.2.1 API"可能是指Quartz Scheduler的API文档,这是一个开源的作业调度框架,可与Spring集成,用于在应用中安排任务执行。虽然它与主题中的XSD文件不直接相关,但当涉及到复杂的缓存策略时,可能需要结合...

    spring+springMVC+mybatis+quartz动态定时任务创建

    在IT行业中,构建高效、可扩展的Web应用是至关重要的,而"spring+springMVC+mybatis+quartz动态定时任务创建"就是一个常见的技术栈,用于实现这样的目标。这个组合充分利用了各组件的优势,提供了强大的后端服务支持...

    Springboot+Mybatis-plus+ SpringMvc+Shiro+Redis企业级报表后台管理系统.rar

    存储过程等),用Redis做中间缓存,缓存数据 实现异步处理,定时任务,整合Quartz Job以及Spring Task 邮件管理功能, 整合spring-boot-starter-mail发送邮件等, 数据源:druid 用户管理,菜单管理,角色管理,代码...

    Quartz+spring定时任务demo

    确保包含 `quartz.jar`、`spring-context.jar` 及其他相关的 Spring 库。 2. **配置 Quartz**:创建 `quartz.properties` 文件来配置 Quartz 的基本属性,如线程池大小、作业存储方式等。还可以在配置文件中指定 ...

    Spring mvc + Mybatis + quartz + swagger 定时任务管理[新增、编辑、删除、修改]

    在这个系统中,Quartz作为核心的定时任务引擎,允许管理员动态创建、编辑、删除和修改定时任务。所有的任务配置信息,包括任务名称、执行时间、触发条件等,都可以存入数据库,便于集中管理和查询。 Swagger则是一...

    Quartz + spring简单配置多个任务调度

    Quartz + spring简单配置多个任务调度 spring配置文件 简单配置

    quartz-spring-demo

    通过 "quartz-spring-demo",开发者可以快速理解如何在 Spring 应用程序中集成和使用 Quartz,从而实现灵活的定时任务调度。这个简单的演示项目是一个学习和实践 Quartz 和 Spring 整合的好起点。

    spring-context-support.jar,quartz-all-1.6.0.jar

    而当我们提到`spring-context-support.jar`和`quartz-all-1.6.0.jar`时,我们是在讨论Spring框架中的任务调度功能,特别是与Quartz库的集成。 `spring-context`是Spring框架的核心模块之一,它提供了上下文...

    spring-context-support-4.2.2和quartz-2.2.3所需Jar包

    标题中的"spring-context-support-4.2.2和quartz-2.2.3所需Jar包"涉及到两个关键的Java库:Spring Context Support 4.2.2版本和Quartz Scheduler 2.2.3版本。这两个库在企业级Java应用开发中扮演着重要角色,特别是...

    spring-context-support-5.3.15-API文档-中英对照版.zip

    包含翻译后的API文档:spring-context-support-5.3.15-javadoc-API文档-中文(简体)-英语-对照版.zip; Maven坐标:org.springframework:spring-context-support:5.3.15; 标签:spring、context、springframework、...

    基于spring-boot+quartz的CRUD任务管理系统源码+项目说明.zip

    基于spring-boot+quartz的CRUD任务管理系统源码+项目说明.zip基于spring-boot+quartz的CRUD任务管理系统源码+项目说明.zip基于spring-boot+quartz的CRUD任务管理系统源码+项目说明.zip基于spring-boot+quartz的CRUD...

    Quartz + spring的开发步骤

    将 Quartz 整合到 Spring 中,可以方便地管理和控制定时任务,使得应用更具灵活性。 **1. 添加依赖** 首先,我们需要在项目中引入 Quartz 和 Spring 的相关依赖。如果是 Maven 项目,可以在 `pom.xml` 文件中添加...

Global site tag (gtag.js) - Google Analytics