任务管理模块 quartz + spring

来源:互联网 发布:mac eclipse 真机调试 编辑:程序博客网 时间:2024/06/10 03:47

任务管理模块的需求:实现对任务的crud操作,定时执行,以及执行结果的查看。由于涉及到CRUD操作,因此持久化是必须的。关于quartz持久化的配置,有很多文章可以参考,这里就不说了,本文主要谈谈持久化实现和其中一些很少有人提及的问题。

1. CRUD操作的实现

对于用ssh框架习惯的人来说,一提到CRUD,hibernate就是当仁不让的选择。笔者想说的是quartz已经完成的事情,为啥你非得再去做一次呢? 事实上只要配置好quartz的store,scheduler一操作jobdetail或trigger,scheduler的内存变化就会反映到数据库里。因此,CUD的操作,通过scheduler进行即可。这里比较麻烦的是R的操作该怎么处理。有两种选择: 1.仍然用scheduler,通过一系列的get****方法去取得jobdetail和trigger的信息,封装后再传到页面;2.使用jdbcTemplate或者hsql直接查询数据库。

第一种方法比较简单,但实现相对繁琐;第二种虽然很容易,但又涉及到一个问题:如何读取blob字段?blob字段对于jobdetail来说存放的是jobdatamap的数据,所以读取blob字段是跳不过的一环。既然,quartz已经实现了持久化,当然这个问题也解决了,因此将quartz的类拿来修改下就可以了,不过quartz是通过resultset来实现的,所以最后笔者选择了jdbc这个最原始的东东。

        DriverManagerDataSource dd =(DriverManagerDataSource)webContext.getBean("dataSource1");

blob的处理可以参考quartz中org.quartz.impl.jdbcjobstore.StdJDBCDelegate的源代码,这里将主要的方法提取出来:

public class BlobDataDelagte {

    public Object getObjectFromBlob(ResultSet rs, String colName)
    throws ClassNotFoundException, IOException, SQLException {
     Object obj = null;
 
     Blob blobLocator = rs.getBlob(colName);
     if (blobLocator != null && blobLocator.length() != 0) {
         InputStream binaryInput = blobLocator.getBinaryStream();
 
         if (null != binaryInput) {
             if (binaryInput instanceof ByteArrayInputStream
                 && ((ByteArrayInputStream) binaryInput).available() == 0 ) {
                 //do nothing
             } else {
                 ObjectInputStream in = new ObjectInputStream(binaryInput);
                 try {
                     obj = in.readObject();
                 } finally {
                     in.close();
                 }
             }
         }
 
     }
     return obj;
 }   

    protected Object getJobDataFromBlob(ResultSet rs, String colName)
    throws ClassNotFoundException, IOException, SQLException {
     if (true) {
         Blob blobLocator = rs.getBlob(colName);
         if (blobLocator != null) {
             InputStream binaryInput = blobLocator.getBinaryStream();
             return binaryInput;
         } else {
             return null;
         }
     }
 
     return getObjectFromBlob(rs, colName);
 }
   
    protected Map<?, ?> convertFromProperty(Properties properties) throws IOException {
        return new HashMap<Object, Object>(properties);
    }

    public Map<?, ?> getMapFromProperties(ResultSet rs, String colName)
    throws ClassNotFoundException, IOException, SQLException {
     Map<?, ?> map;
     InputStream is = (InputStream) getJobDataFromBlob(rs, colName);
     if(is == null) {
         return null;
     }
     Properties properties = new Properties();
     if (is != null) {
         try {
             properties.load(is);
         } finally {
             is.close();
         }
     }
     map = convertFromProperty(properties);
     return map;
 } 
 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub

 }

}

调用方法如下:

Map<?, ?> map = (Map<?, ?>)   new BlobDataDelagte().getObjectFromBlob(rs, "JOB_DATA");

String tbean =(String)map.get("targetBean");


2. quartz调度 非JOBDETAIL类

quartz调度非JOBDETAIL类,在很多文章都有提及,使用spring的org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean类封装下就可以了。但是

一涉及到quartz持久化的时候,这个类会抛异常:

Caused by: java.io.NotSerializableException: Unable to serialize JobDataMap for insertion into database because the value of property 'methodInvoker' is not serializable: org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean

这个异常的意思就是MethodInvokingJobDetailFactoryBean不支持持久化功能。解决办法:

http://jira.springframework.org/browse/SPR-3797 下载两个文件:
frameworkx.springframework.scheduling.quartz.BeanInvokingJobDetailFactoryBean
frameworkx.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean

这两个class有着不同的应用,对于BeanInvokingJobDetailFactoryBean来说,它可以触发非静态的方法;
而MethodInvokingJobDetailFactoryBean可以触发静态和非静态方法。由于这两个类都是用来改进MethodInvokingJobDetailFactoryBean的,因此对要调用的javabean的查找都是通过applicationContext进行的,因此在使用过程中需要做些修正,在applicationContext找不到javabean的情况下,需要通过反射机制来创建javabean。

 Object bean =null;
    try
    {
     bean = applicationContext.getBean(targetBean);
    }
    catch(Exception e)
    {
     if (bean==null)
     {
      bean =Class.forName(targetBean).newInstance();
     } 
     
    }


3.执行结果的查看

对于用户来说,一个很好的体验就是能够跟踪和了解任务的执行情况和结果。这个属于quartz的题外话,quartz 自身并不提供查看执行结果的功能。若要实现,需要自己处理,这里需要考量两个问题:对于像邮件通知、短信提醒这样的类要怎么提供自身的执行情况和进度?对于数据库存储过程要怎么提供自身的执行情况和进度? 一个最简单的办法就是在数据库建这样的表,然后相关任务类、存储过程不断对这个表进行添加和更新操作,在页面上通过轮询来获取 任务的执行情况和结果。这里只简单的用ORACLE的查询结果进行展示:

 


 4. XML的持久化数据

 使用spring的人都很熟悉怎么使用XML配置各类javabean,但是很少有人会提及将spring容器内的javabean的最新变动存回xml,quartz的数据虽然已经持久化在数据表里了,但是还是有必要将变动情况也存放在XML文件里,毕竟大家都晓得:“不要把所有鸡蛋都放在同一个篮子里”。对于XML的读写,有很多文章可以借鉴,这里不详述了,只是提供个思路,仅供参考。

原创粉丝点击