`
jsufly
  • 浏览: 14178 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

如何用代码控制Quartz的启停

阅读更多
http://www.iteye.com/topic/440687

Spring中如何使用Quartz就不必说了,这里说说如果动态设定cron。
这个要解决3个问题:
1.将用户输入转换为Cron表达式
2.安全的重启quartz
3.程序启动的时候,从数据库中读取cron(而非spring配置文件中写死的那个)。
因为derpvail急着用,所以先说第3个。
动态读取数据库中的Cron,作为CronTriggerBean的属性
从数据库中读取cron,需要做一个CronExpressionFactoryBean,它是一个Spring的FactoryBean,可以读取数据库,并创建一个CronExpression对象:
Java代码
public class CronFactoryBean implements FactoryBean {  
  private static Logger logger = LoggerFactory.getLogger(CronFactoryBean.class);  
  @Autowired 
  @Qualifier("defaultFreq")  
  private String defaultCron;  
  /** 
   * 用于取得CRON表达式. 
   */ 
  @Autowired(required = true)  
  private CronManager cronManager;  
    
    
  /** 
   * 从数据库中取得CRON表达式,如果数据库中没有则取缺省值. 
   * @see EmailConstants#DEFALUT_CRON 
   */ 
  @Override 
  public Object getObject() throws Exception {  
    //如何读取数据库,就省了  
    String cronEx = cronManager.getCronExpression();  
    if(StringUtils.isBlank(cronEx)) {  
      return new CronExpression(defaultCron);  
    }  
    return new CronExpression(cronEx.trim());  
  }  
 
  @SuppressWarnings("unchecked")  
  @Override 
  public Class getObjectType() {  
    return CronExpression.class;  
  }  
 
  @Override 
  public boolean isSingleton() {  
    return true;  
  }  
 


public class CronFactoryBean implements FactoryBean {
  private static Logger logger = LoggerFactory.getLogger(CronFactoryBean.class);
  @Autowired
  @Qualifier("defaultFreq")
  private String defaultCron;
  /**
   * 用于取得CRON表达式.
   */
  @Autowired(required = true)
  private CronManager cronManager;
 
 
  /**
   * 从数据库中取得CRON表达式,如果数据库中没有则取缺省值.
   * @see EmailConstants#DEFALUT_CRON
   */
  @Override
  public Object getObject() throws Exception {
    //如何读取数据库,就省了
    String cronEx = cronManager.getCronExpression();
    if(StringUtils.isBlank(cronEx)) {
      return new CronExpression(defaultCron);
    }
    return new CronExpression(cronEx.trim());
  }

  @SuppressWarnings("unchecked")
  @Override
  public Class getObjectType() {
    return CronExpression.class;
  }

  @Override
  public boolean isSingleton() {
    return true;
  }

}


然后呢,就是吧这个CronExpression对象注入到CronTriggerBean,但是CronTriggerBean的setCronExpression方法是重载的,本人不知道如何注入重载方法,所以只好继承了CronTriggerBean,添加了一个setCron方法,一遍于Spring的注入:
Java代码
/** 
* FIXME:因为目前不知道如何实现重载方法的注入,而<code>CronTrigger</code> 
* 的<code>setCronExpression</code>既可以用<code>CronExpression</code> 
* 对象作为参数也可以用String作为参数,这就产生了不确定性。所以,我们extends了 
* <code>CronTriggerBean</code>,提供{@link #setCron(CronExpression)} 
* 方法,避免这种不确定性。 
* @author Sam 

*/ 
public class CronTriggerBeanEx extends CronTriggerBean {  
  /** 
   * 调用父类的{@link CronTriggerBean#setCronExpression(CronExpression)} 
   * 方法. 
   */ 
  public void setCron(CronExpression cronExpression) {  
    this.setCronExpression(cronExpression);  
  }  


/**
* FIXME:因为目前不知道如何实现重载方法的注入,而<code>CronTrigger</code>
* 的<code>setCronExpression</code>既可以用<code>CronExpression</code>
* 对象作为参数也可以用String作为参数,这就产生了不确定性。所以,我们extends了
* <code>CronTriggerBean</code>,提供{@link #setCron(CronExpression)}
* 方法,避免这种不确定性。
* @author Sam
*
*/
public class CronTriggerBeanEx extends CronTriggerBean {
  /**
   * 调用父类的{@link CronTriggerBean#setCronExpression(CronExpression)}
   * 方法.
   */
  public void setCron(CronExpression cronExpression) {
    this.setCronExpression(cronExpression);
  }
}


然后就是在spring中配置这两个Bean了,和普通的quartz类似,只不过cronExpression属性改为了cron属性:
Xml代码
<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd"> 
<beans default-lazy-init="false"> 
    <bean id="seismicEmailCronTrigger" 
        class="datashare.email.admin.jobs.CronTriggerBeanEx">          
        <property name="jobDetail" ref="seismicEmailJobDetail" /> 
        <property name="cron"> 
            <bean class="datashare.email.admin.jobs.CronFactoryBean"> 
              </property> 
            </bean> 
        </property> 
    </bean> 
</beans> 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans default-lazy-init="false">
<bean id="seismicEmailCronTrigger"
class="datashare.email.admin.jobs.CronTriggerBeanEx">
<property name="jobDetail" ref="seismicEmailJobDetail" />
<property name="cron">
<bean class="datashare.email.admin.jobs.CronFactoryBean">
  </property>
</bean>
</property>
</bean>
</beans>

注意default-lazy-init="false",这样,quartz就可以在项目启动的时候,读取数据库中的cron了。
先写到这里,开会了....
安全的重启quartz
貌似网上的文章都不太对,下面的这方法可以正常运行,在此之前,你应该把ApplicationContext注入,可以用ApplicationContextAware接口,也可以用@Autowired注解:
Java代码
@Autowired(required = true)  
  private ApplicationContext ctx;  
 
/** 
   * 如果cron改变,则重新启动Quartz任务。 
    
   * @param signCron 用户输入的CRON,你可以把它先存入数据库 
   * @throws ApplicationException 如果CRON无法解析,或原来的任务无法关闭,以及无法启动新任务. 
   */ 
  private void restartJobs(String signCron) {  
    if(StringUtils.isBlank(signCron)) {  
      logger.warn("CRON未设定。");  
      return;  
    }  
    //trim一下,难保没有空格  
    signCron = signCron.trim();  
    //得到trigger  
      
    CronTrigger signCronTrigger = (CronTrigger) ctx.getBean("signEmailCronTrigger", CronTrigger.class);  
    //如果频率都有变,则不必重新启动.  
    if(signCron.equals(signCronTrigger.getCronExpression())) {  
      logger.info("前兆和测震发送频率都未改变,Quartz不必重新启动.");  
      return;  
    }  
    //下面是关键  
    //得到SchedulerFactoryBean的实例,注意beanName前面的&符号  
    SchedulerFactoryBean schedulerFactory = (SchedulerFactoryBean) ctx.getBean("&emailSchedulerFactory");  
    try {  
      //重新设定trigger  
      signCronTrigger.setCronExpression(signCron);  
      schedulerFactory.destroy(); //关闭原来的任务  
      schedulerFactory.afterPropertiesSet(); //启动新的任务  
      logger.info("XXX任务启动成功.");  
    } catch (ParseException e) {  
      throw new ApplicationException("Cron表达式解析错误." + e.getMessage());  
    } catch (SchedulerException e) {  
      e.printStackTrace();  
      throw new ApplicationException("关闭定时任务出现异常.");  
    } catch (Exception e) {  
      e.printStackTrace();  
      throw new ApplicationException("启动定时任务出现异常.");  
    }      
  }  
//我原来的代码和这个略有不同,这段代码没有调试过(在JE上编辑的),不过应该可以运行 

@Autowired(required = true)
  private ApplicationContext ctx;

/**
   * 如果cron改变,则重新启动Quartz任务。
  
   * @param signCron 用户输入的CRON,你可以把它先存入数据库
   * @throws ApplicationException 如果CRON无法解析,或原来的任务无法关闭,以及无法启动新任务.
   */
  private void restartJobs(String signCron) {
    if(StringUtils.isBlank(signCron)) {
      logger.warn("CRON未设定。");
      return;
    }
    //trim一下,难保没有空格
    signCron = signCron.trim();
    //得到trigger
   
    CronTrigger signCronTrigger = (CronTrigger) ctx.getBean("signEmailCronTrigger", CronTrigger.class);
    //如果频率都有变,则不必重新启动.
    if(signCron.equals(signCronTrigger.getCronExpression())) {
      logger.info("前兆和测震发送频率都未改变,Quartz不必重新启动.");
      return;
    }
    //下面是关键
    //得到SchedulerFactoryBean的实例,注意beanName前面的&符号
    SchedulerFactoryBean schedulerFactory = (SchedulerFactoryBean) ctx.getBean("&emailSchedulerFactory");
    try {
      //重新设定trigger
      signCronTrigger.setCronExpression(signCron);
      schedulerFactory.destroy(); //关闭原来的任务
      schedulerFactory.afterPropertiesSet(); //启动新的任务
      logger.info("XXX任务启动成功.");
    } catch (ParseException e) {
      throw new ApplicationException("Cron表达式解析错误." + e.getMessage());
    } catch (SchedulerException e) {
      e.printStackTrace();
      throw new ApplicationException("关闭定时任务出现异常.");
    } catch (Exception e) {
      e.printStackTrace();
      throw new ApplicationException("启动定时任务出现异常.");
    }   
  }
//我原来的代码和这个略有不同,这段代码没有调试过(在JE上编辑的),不过应该可以运行

先写到这里,开会了,其实下一个问题我也没有什么好办法....

将用户输入转换为Cron表达式,这个问题我已经解决了。
因为我的都是定时发布任务,时间形如:2008-08-08 11:08:28这样的形式,所以转换方法参照cron的表达式还是很好写的。
分享到:
评论

相关推荐

    Quartz+TopShelf实现Windows服务作业

    这样,我们就可以在后台无须用户交互的情况下,按照预设的计划执行任务,并且可以通过服务管理工具控制服务的启停、暂停和恢复。 在QTDemo这个项目中,我们可以看到如何将这两个库整合起来。项目可能包含了配置文件...

    Spring Quartz集成

    当需要更复杂的动态配置,比如任务的启停或者定时规则的变更,不能仅靠静态配置完成。这时,可以自定义实现Quartz的相关接口,如`TriggerListener`和`JobListener`,来监听和控制任务的生命周期。此外,可以使用...

    Spring Boot如何实现定时任务的动态增删启停详解

    Spring Boot 实现定时任务的动态增删启停详解 在 Spring Boot 项目中,实现定时任务的动态增删启停是非常重要的。传统的方法是使用 Quartz 框架,但是这种方法需要依赖其它框架,可能会导致项目的臃肿和复杂。因此...

    SSH+quartz实现的可动态配置时间规则的定时任务

    6. **动态开启和关闭任务**:除了配置时间规则,还应支持对任务的启停操作。这涉及到Quartz的API调用,例如`scheduler.pauseJob()`和`scheduler.resumeJob()`,以便在运行时暂停或恢复特定的定时任务。 综上所述,...

    【SpringBoot】廿五、SpringBoot中使用Quartz管理定时任务.pdf

    之前我们都是在项目中规定这个定时任务什么时候启动,到时间了便会自己启动,那么我们想要停止这个定时任务的时候,就需要去改动代码,还得启停服务器,这是非常不友好的事情。 直至遇见 Quartz ,利用图形界面可视...

    asp.net定时任务(定时器)

    在ASP.NET中,可以在`Application_Start`和`Application_End`事件中控制定时器的启停,确保服务器启动时开始,关闭时停止。 6. **注意线程安全**: 在多用户环境中,必须考虑线程安全问题。如果定时任务修改共享...

    xmljava系统源码-renren-fast:基于renren-fast开源框架的,二次开发搭建的性能、接口测试平台,同时集成三方工具的启停

    灵活的权限控制,可控制到页面或按钮,满足绝大部分的权限需求 页面交互使用Vue2.x,极大的提高了开发效率 完善的代码生成机制,可在线生成entity、xml、dao、service、html、js、sql代码,减少70%以上的开发任务 ...

    OpenAuth.Core后台管理框架 v3.0.1

    6、基于Quartz.Net的定时任务控制,可随时启/停,可视化配置Cron表达式功能 7、基于CodeSmith的代码生成功能,可快速生成带有头/明细结构的页面 8、支持sqlserver、mysql数据库,理论上支持所有数据库 9、集成...

    任务调度工具 xxl

    - **动态管理**:任务的增删改查、启停操作、任务分组等都可以在线完成,无需重启调度服务。 - **丰富的调度策略**:支持定时、周期、一次性、依赖等多种调度策略。 - **日志追踪**:详细记录任务执行日志,便于...

    OpenAuth.Core后台管理框架-.net

    6、基于Quartz.Net的定时任务控制,可随时启/停,可视化配置Cron表达式功能 7、基于CodeSmith的代码生成功能,可快速生成带有头/明细结构的页面 8、支持sqlserver、mysql数据库,理论上支持所有数据库 9、集成...

Global site tag (gtag.js) - Google Analytics