全文检索系统需要定时建立索引,故需要定时执行某些任务,以下是实现思路:
单次任务使用timer.schedule(new task(),Date date)实现。
每天任务与每周任务使用timer.scheduleAtFixedRate(new task(),delay,period)实现,周期分别为24*1000/7*24*1000。
每月任务同每天任务,但周期不确定,思虑良久,采用java反射机制动态修改周期。
代码如下:
1、创建ServletContextListener类
package org.fulltext.task; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener; /** * Application Lifecycle Listener implementation class TaskListener * */ @WebListener public class TaskListener implements ServletContextListener { /** * Default constructor. */ public TaskListener() { // TODO Auto-generated constructor stub } /** * @see ServletContextListener#contextDestroyed(ServletContextEvent) */ public void contextDestroyed(ServletContextEvent arg0) { // TODO Auto-generated method stub TaskManager.destoryTimer(); } /** * @see ServletContextListener#contextInitialized(ServletContextEvent) */ public void contextInitialized(ServletContextEvent arg0) { // TODO Auto-generated method stub TaskManager taskManager=new TaskManager(); } }
2、修改web.xml文件,在web-app下添加时间侦听。
<listener> <listener-class> org.fulltext.task.TaskListener </listener-class> </listener>
3、创建taskManager类,该类通过timer执行定时任务,是定时任务的核心。
package org.fulltext.task; public class TaskManager { static Logger logger=Logger.getLogger("logfile"); public static List<Timer> timers=new ArrayList<Timer>(); public TaskManager(){ List<Taskconfig> taskconfigs=new ArrayList<Taskconfig>(); TaskconfigDAO taskconfigDAO=new TaskconfigDAO(); taskconfigs=taskconfigDAO.findAll(); SimpleDateFormat simpleDateFormat; for (int i = 0; i <taskconfigs.size(); i++) { timers.add(i,new Timer("Tasktimer"+i,true)); } for (int i = 0; i < taskconfigs.size(); i++) { if(taskconfigs.get(i).getTaskstate().trim().equals("0")||taskconfigs.get(i).getTaskstate().trim().equals("3")){ } else{ switch (taskconfigs.get(i).getTaskperiod().trim()) { case "once": if (taskconfigs.get(i).getTaskexcetime().before(new Date())) { simpleDateFormat=new SimpleDateFormat("HH:mm:ss"); logger.warn("单次任务调度失败,原因:执行时间小于当前时间,"+"任务名:"+taskconfigs.get(i).getTaskname()+",任务所属"+taskconfigs.get(i).getTasktype()+",任务操作:" +taskconfigs.get(i).getTaskoperate()+" ,任务周期:"+taskconfigs.get(i).getTaskperiod()+",任务执行时间:"+simpleDateFormat.format(taskconfigs.get(i).getTaskexcetime()).toString()); taskconfigs.get(i).setTaskstate("3"); taskconfigDAO.save(taskconfigs.get(i)); } else{ simpleDateFormat=new SimpleDateFormat("HH:mm:ss"); logger.info("单次任务调度成功,任务名:"+taskconfigs.get(i).getTaskname()+",任务所属"+taskconfigs.get(i).getTasktype()+",任务操作:" +taskconfigs.get(i).getTaskoperate()+" ,任务周期:"+taskconfigs.get(i).getTaskperiod()+",任务执行时间:"+simpleDateFormat.format(taskconfigs.get(i).getTaskexcetime()).toString()); if ("recreate_index".equals(taskconfigs.get(i).getTaskoperate().trim())) { timers.get(i).schedule(new RecreateIndexTask(taskconfigs.get(i)), taskconfigs.get(i).getTaskexcetime()); }else { timers.get(i).schedule(new CrawlIndexTask(taskconfigs.get(i)), taskconfigs.get(i).getTaskexcetime()); } } break; case "day": long PERIOD_DAY = 24*60*60*1000; Calendar now=Calendar.getInstance(); Calendar excetimeCalendar=Calendar.getInstance(); excetimeCalendar.setTime(taskconfigs.get(i).getTaskexcetime()); now.set(Calendar.HOUR_OF_DAY, excetimeCalendar.get(Calendar.HOUR_OF_DAY)); now.set(Calendar.MINUTE, excetimeCalendar.get(Calendar.MINUTE)); now.set(Calendar.SECOND, excetimeCalendar.get(Calendar.SECOND)); Date excDate=now.getTime(); while(excDate.before(new Date())){ now.add(Calendar.DAY_OF_MONTH, 1); excDate=now.getTime(); } simpleDateFormat=new SimpleDateFormat("HH:mm:ss"); logger.info("每天任务调度成功,任务名:"+taskconfigs.get(i).getTaskname()+",任务所属"+taskconfigs.get(i).getTasktype()+",任务操作:" +taskconfigs.get(i).getTaskoperate()+" ,任务周期:"+taskconfigs.get(i).getTaskperiod()+",任务执行时间:"+simpleDateFormat.format(taskconfigs.get(i).getTaskexcetime()).toString()); if ("recreate_index".equals(taskconfigs.get(i).getTaskoperate().trim())) { timers.get(i).scheduleAtFixedRate(new RecreateIndexTask(taskconfigs.get(i)), excDate,PERIOD_DAY); }else { timers.get(i).scheduleAtFixedRate(new CrawlIndexTask(taskconfigs.get(i)),excDate,PERIOD_DAY); } break; case "week": long PERIOD_WEEK = 7*24*60*60*1000; Calendar week_now=Calendar.getInstance(); Calendar excetimeweek=Calendar.getInstance(); excetimeweek.setTime(taskconfigs.get(i).getTaskexcetime()); week_now.set(Calendar.DAY_OF_WEEK, new Integer(taskconfigs.get(i).getTaskweekday().trim())); week_now.set(Calendar.HOUR_OF_DAY, excetimeweek.get(Calendar.HOUR_OF_DAY)); week_now.set(Calendar.MINUTE, excetimeweek.get(Calendar.MINUTE)); week_now.set(Calendar.SECOND, excetimeweek.get(Calendar.SECOND)); Date wexcDate=week_now.getTime(); System.out.println(wexcDate+"===="+new Date()); while(wexcDate.before(new Date())){ week_now.add(Calendar.DAY_OF_MONTH, 7); wexcDate=week_now.getTime(); } simpleDateFormat=new SimpleDateFormat("HH:mm:ss"); logger.info("每周任务调度成功,任务名:"+taskconfigs.get(i).getTaskname()+",任务所属"+taskconfigs.get(i).getTasktype()+",任务操作:" +taskconfigs.get(i).getTaskoperate()+" ,任务周期:"+taskconfigs.get(i).getTaskperiod()+",任务执行时间:"+simpleDateFormat.format(taskconfigs.get(i).getTaskexcetime()).toString()); if ("recreate_index".equals(taskconfigs.get(i).getTaskoperate().trim())) { System.out.println(wexcDate); timers.get(i).scheduleAtFixedRate(new RecreateIndexTask(taskconfigs.get(i)), wexcDate,PERIOD_WEEK); }else { timers.get(i).scheduleAtFixedRate(new CrawlIndexTask(taskconfigs.get(i)),wexcDate,PERIOD_WEEK); } break; case "month": Calendar month_now=Calendar.getInstance(); Calendar excetime_month=Calendar.getInstance(); excetime_month.setTime(taskconfigs.get(i).getTaskexcetime()); while (month_now.getActualMaximum(Calendar.DAY_OF_MONTH)<new Integer(taskconfigs.get(i).getTaskmonday().trim())) { logger.warn("调度每月任务,因当前月份:"+(month_now.get(Calendar.MONTH)+1)+"月没有"+taskconfigs.get(i).getTaskmonday().trim()+"号,最大天数为:"+month_now.getActualMaximum(Calendar.DAY_OF_MONTH)+"故延后一月"); month_now.add(Calendar.MONTH, 1); } month_now.set(Calendar.DAY_OF_MONTH, new Integer(taskconfigs.get(i).getTaskmonday().trim())); month_now.set(Calendar.HOUR_OF_DAY, excetime_month.get(Calendar.HOUR_OF_DAY)); month_now.set(Calendar.MINUTE, excetime_month.get(Calendar.MINUTE)); month_now.set(Calendar.SECOND, excetime_month.get(Calendar.SECOND)); Date monthDate=month_now.getTime(); while(monthDate.before(new Date())){ month_now.add(Calendar.MONTH, 1); monthDate=month_now.getTime(); } long PERIOD_month = month_now.getActualMaximum(Calendar.DAY_OF_MONTH)*24*60*60*1000L; simpleDateFormat=new SimpleDateFormat("HH:mm:ss"); logger.info("每月任务调度成功,任务名:"+taskconfigs.get(i).getTaskname()+",任务所属"+taskconfigs.get(i).getTasktype()+",任务操作:" +taskconfigs.get(i).getTaskoperate()+" ,任务周期:"+taskconfigs.get(i).getTaskperiod()+",任务执行时间:"+simpleDateFormat.format(taskconfigs.get(i).getTaskexcetime()).toString()); if ("recreate_index".equals(taskconfigs.get(i).getTaskoperate().trim())) { timers.get(i).scheduleAtFixedRate(new ReIndexOfMonth(taskconfigs.get(i)), monthDate,PERIOD_month); }else { timers.get(i).scheduleAtFixedRate(new CrawlIndexOfMonth(taskconfigs.get(i)), monthDate,PERIOD_month); } break; default: break; } } } HibernateSessionFactory.closeSession(); } public static void destoryTimer() { for(int i=0;i<timers.size();i++){ timers.get(i).cancel(); timers.get(i).purge(); } Map<Thread,StackTraceElement[]> threadmMap=Thread.getAllStackTraces(); Set<Thread> keyThreads=threadmMap.keySet(); for (Iterator<Thread> it = keyThreads.iterator(); it.hasNext();) { Thread thread=it.next(); if(thread.getName().indexOf("Tasktimer")>=0) thread.interrupt(); } timers.clear(); System.gc(); } }
4、最后创建timerTask类,该类包含run方法,run方法中放置需要执行的任务代码。
package org.fulltext.task; import java.lang.reflect.Field; import java.util.TimerTask; import org.apache.commons.collections.map.StaticBucketMap; public class ExecuteTask extends TimerTask{ public void run() { // TODO Auto-generated method stub System.out.println("运行计划任务"); setDeclaredField(TimerTask.class, this, "period", 1000); } }
5、每月任务周期不固定,使用java反射机制动态修改执行周期字段。
package org.fulltext.task; import java.lang.reflect.Field; import java.util.TimerTask; import org.apache.commons.collections.map.StaticBucketMap; public class ExecuteTask extends TimerTask{ static int p=0; static boolean setDeclaredField(Class<?> clazz, Object obj, String name, int value) { p=p+value; try { Field field = clazz.getDeclaredField(name); field.setAccessible(true); field.set(obj, p); return true; } catch (Exception ex) { ex.printStackTrace(); return false; } } @Override public void run() { // TODO Auto-generated method stub System.out.println("测试java反射机制"); setDeclaredField(TimerTask.class, this, "period", 1000); } }
编写timer时,需要释放资源,否则系统重启或重新加载任务会继续调度执行。 在ServletContextListener的contextDestroyed方法中添加删除timer取消及删除功能。