有一种人,徘徊在牛a和牛c之间。。。
在工作中经常有业务是异步的:
1.用户办了一个订单,填写了一个反馈,当订单竣工的时候要发短信通知客户,说你办理的业务现在成功了
2.用户定购了一个账单,要每个月都要给用用户发送 上月用户账单内容到指定的 邮箱 或者 手机
3.有些统计的内容 需要每天计算 插到数据库里
等等,这都需要有个自动任务来管理,定时执行这些任务,并且统一管理。
公司一牛人写了一个自动任务的框架,可以定时帮助我们执行一些任务,并且由一张表(neb_trigger)统一管理,在工作中我们就是使用的 这个自动任务的框架 来完成 某些异步业务 或者定时任务的
我们项目的架构 是前台的action调用 后台的ejb ,因此自动任务 写在ejb里,大致的原理如下:
1.首先 自动任务(Trigger)维护着 一张表 (netb_trigger),她根据表中任务的信息,来执行业务方法(利用反射),表中有个字段是 业务方法的实现类的
2.定义了一个接口 TriggerTask ,只有一个方法 doTask(),何使用到自动任务的 业务都需要实现这个接口
3.Trigger 是一个会话bean ,其实现方法只有 一个业务方法 runTask(),它会调用 TriggerTask 接口中的runTask()方法 利用反射来执行 业务方法
4.为了对 netb_trigger 进行 添加,修改,删除 自动任务,又写了一个 TriggerManage类,这个类是用来供Action层来添加删除和修改自动任务的,其中有个方法
public static String addTask(
String taskDesc,
String clazz,
String inParam,
String cycle,
String cycleLimit,
String dayLimit,
String hourLimit) throws Exception
自动任务将 利用 传递的clazz 来 反射调用业务方法
目标:通过 一个main方法去 掉部署在jboss的ejb的自动任务,然他去定时执行执行业务方法
为了让大家能使用到这个自动任务框架 我一步一步 让这个自动任务跑起来!!flow me,let's go!!
首要条件:需要有jboss ,hibernate,mysql 环境
步骤1:建立 自动任务状态表,以及对应的实体
任务表:netb_trigger
- CREATE TABLE `netb_trigger` (
- `ID` char(255) NOT NULL,
- `TASKDESC` char(255) DEFAULT NULL,
- `STATE` int(10) DEFAULT NULL,
- `CLAZZ` char(255) DEFAULT NULL,
- `INPARAM` char(255) DEFAULT NULL,
- `CYCLE` char(255) DEFAULT NULL,
- `CYCLELIMIT` char(255) DEFAULT NULL,
- `DAYLIMIT` char(255) DEFAULT NULL,
- `HOURLIMIT` char(255) DEFAULT NULL,
- `CREATETIME` datetime DEFAULT NULL,
- `LASTTIME` datetime DEFAULT NULL,
- PRIMARY KEY (`ID`)
- ) ENGINE=InnoDB DEFAULT CHARSET=gbk
CREATE TABLE `netb_trigger` (
`ID` char(255) NOT NULL,
`TASKDESC` char(255) DEFAULT NULL,
`STATE` int(10) DEFAULT NULL,
`CLAZZ` char(255) DEFAULT NULL,
`INPARAM` char(255) DEFAULT NULL,
`CYCLE` char(255) DEFAULT NULL,
`CYCLELIMIT` char(255) DEFAULT NULL,
`DAYLIMIT` char(255) DEFAULT NULL,
`HOURLIMIT` char(255) DEFAULT NULL,
`CREATETIME` datetime DEFAULT NULL,
`LASTTIME` datetime DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=gbk
实体Tirgger
- package cn.com.xinli.netb.entitys;
- import java.io.Serializable;
- import java.sql.Timestamp;
- /**
- * 触发任务表
- * @author diaoyf
- *
- */
- public class Trigger implements Serializable
- {
- public static final long serialVersionUID = 1;
- /** id */
- private String id;
- /** 触发任务描述 */
- private String taskDesc;
- /** 触发状态 0:允许触发 1:取消触发 */
- private int state;
- /**
- * 回调对象的包、类路径名
- * 触发管理器根据此包、类路径名,通过反射机制实例化对象
- */
- private String clazz;
- /** 回调方法输入参数 */
- private String inParam;
- /**
- * 触发周期
- * <li>atonce 表示一次(由小时触发器管理)</li>
- * <li>min 表示每分</li>
- * <li>hour 表示每小时</li>
- * <li>day 表示每天</li>
- * <li>month 表示每月</li>
- * <li>3month 表示每季度</li>
- * <li>year 表示每年</li>
- */
- private String cycle;
- /**
- * 触发时间限制
- * 格式"2007/10/2 8:15:28-2007/10/3 18:15:30",表示任务存在时间
- * 格式"-", 表示无触发时间限制
- *
- */
- private String cycleLimit;
- /**
- * 触发日期限制
- * 如月账单反馈限制在每月10~15日(包括15日),dayLimit设置格式为"10-15";
- * 如限制在每月10日,设置格式为"10-10";
- * 如果没有日期限制,设置格式为"-"
- * 如果起始日期大于终止日期,如"25-10",表示当月25日到下月10日
- */
- private String dayLimit;
- /**
- * 触发时间限制,时间规则最小"00:00",最大"23:59"
- * 如邮件反馈限制在每天8~17时(8:00~17:59),hourLimit设置格式为"8:00-17:59";
- * 如限制在12时(12:00~12:59),设置格式为"12:00-12:59".
- * 如果没有时间限制,设置格式为"-"
- * 如果起始日期大于终止日期,如"23:00-8:59",表示当日23:00到下一日8:59
- */
- private String hourLimit;
- /** 触发任务创建时间 */
- private Timestamp createTime;
- /** 最后一次触发时间 */
- private Timestamp lastTime;
- public String getId()
- {
- return id;
- }
- public void setId(String id)
- {
- this.id = id;
- }
- public String getTaskDesc()
- {
- return taskDesc;
- }
- public void setTaskDesc(String taskDesc)
- {
- this.taskDesc = taskDesc;
- }
- public int getState()
- {
- return state;
- }
- public void setState(int state)
- {
- this.state = state;
- }
- public String getClazz()
- {
- return clazz;
- }
- public void setClazz(String clazz)
- {
- this.clazz = clazz;
- }
- public String getInParam()
- {
- return inParam;
- }
- public void setInParam(String inParam)
- {
- this.inParam = inParam;
- }
- public String getCycle()
- {
- return cycle;
- }
- public void setCycle(String cycle)
- {
- this.cycle = cycle;
- }
- public String getCycleLimit()
- {
- return cycleLimit;
- }
- public void setCycleLimit(String cycleLimit)
- {
- this.cycleLimit = cycleLimit;
- }
- public String getDayLimit()
- {
- return dayLimit;
- }
- public void setDayLimit(String dayLimit)
- {
- this.dayLimit = dayLimit;
- }
- public String getHourLimit()
- {
- return hourLimit;
- }
- public void setHourLimit(String hourLimit)
- {
- this.hourLimit = hourLimit;
- }
- public Timestamp getCreateTime()
- {
- return createTime;
- }
- public void setCreateTime(Timestamp createTime)
- {
- this.createTime = createTime;
- }
- public Timestamp getLastTime()
- {
- return lastTime;
- }
- public void setLastTime(Timestamp lastTime)
- {
- this.lastTime = lastTime;
- }
- }
package cn.com.xinli.netb.entitys;
import java.io.Serializable;
import java.sql.Timestamp;
/**
* 触发任务表
* @author diaoyf
*
*/
public class Trigger implements Serializable
{
public static final long serialVersionUID = 1;
/** id */
private String id;
/** 触发任务描述 */
private String taskDesc;
/** 触发状态 0:允许触发 1:取消触发 */
private int state;
/**
* 回调对象的包、类路径名
* 触发管理器根据此包、类路径名,通过反射机制实例化对象
*/
private String clazz;
/** 回调方法输入参数 */
private String inParam;
/**
* 触发周期
* <li>atonce 表示一次(由小时触发器管理)</li>
* <li>min 表示每分</li>
* <li>hour 表示每小时</li>
* <li>day 表示每天</li>
* <li>month 表示每月</li>
* <li>3month 表示每季度</li>
* <li>year 表示每年</li>
*/
private String cycle;
/**
* 触发时间限制
* 格式"2007/10/2 8:15:28-2007/10/3 18:15:30",表示任务存在时间
* 格式"-", 表示无触发时间限制
*
*/
private String cycleLimit;
/**
* 触发日期限制
* 如月账单反馈限制在每月10~15日(包括15日),dayLimit设置格式为"10-15";
* 如限制在每月10日,设置格式为"10-10";
* 如果没有日期限制,设置格式为"-"
* 如果起始日期大于终止日期,如"25-10",表示当月25日到下月10日
*/
private String dayLimit;
/**
* 触发时间限制,时间规则最小"00:00",最大"23:59"
* 如邮件反馈限制在每天8~17时(8:00~17:59),hourLimit设置格式为"8:00-17:59";
* 如限制在12时(12:00~12:59),设置格式为"12:00-12:59".
* 如果没有时间限制,设置格式为"-"
* 如果起始日期大于终止日期,如"23:00-8:59",表示当日23:00到下一日8:59
*/
private String hourLimit;
/** 触发任务创建时间 */
private Timestamp createTime;
/** 最后一次触发时间 */
private Timestamp lastTime;
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public String getTaskDesc()
{
return taskDesc;
}
public void setTaskDesc(String taskDesc)
{
this.taskDesc = taskDesc;
}
public int getState()
{
return state;
}
public void setState(int state)
{
this.state = state;
}
public String getClazz()
{
return clazz;
}
public void setClazz(String clazz)
{
this.clazz = clazz;
}
public String getInParam()
{
return inParam;
}
public void setInParam(String inParam)
{
this.inParam = inParam;
}
public String getCycle()
{
return cycle;
}
public void setCycle(String cycle)
{
this.cycle = cycle;
}
public String getCycleLimit()
{
return cycleLimit;
}
public void setCycleLimit(String cycleLimit)
{
this.cycleLimit = cycleLimit;
}
public String getDayLimit()
{
return dayLimit;
}
public void setDayLimit(String dayLimit)
{
this.dayLimit = dayLimit;
}
public String getHourLimit()
{
return hourLimit;
}
public void setHourLimit(String hourLimit)
{
this.hourLimit = hourLimit;
}
public Timestamp getCreateTime()
{
return createTime;
}
public void setCreateTime(Timestamp createTime)
{
this.createTime = createTime;
}
public Timestamp getLastTime()
{
return lastTime;
}
public void setLastTime(Timestamp lastTime)
{
this.lastTime = lastTime;
}
}
步骤2:建立 trigger ejb 的本地接口和远程接口,Bean实现
TriggerBean.java
- package cn.com.xinli.netb.ejb.trigger.service;
- import java.rmi.RemoteException;
- import java.util.Date;
- import javax.ejb.SessionBean;
- import org.apache.log4j.Logger;
- import cn.com.xinli.netb.ejb.trigger.TriggerTask;
- public class TriggerBean implements SessionBean
- {
- static Logger log = Logger.getLogger(TriggerBean.class);
- private javax.ejb.SessionContext m_ctx = null;
- /**
- * Sets the session context. Required by EJB spec.
- *
- * @param ctx
- * A SessionContext object.
- */
- public void setSessionContext(javax.ejb.SessionContext ctx)
- {
- m_ctx = ctx;
- }
- /**
- * Creates a bean. Required by EJB spec.
- *
- * @exception throws
- * CreateException.
- */
- public void ejbCreate() throws javax.ejb.EJBException,
- javax.ejb.CreateException
- {
- }
- /**
- * Removes the bean. Required by EJB spec.
- */
- public void ejbRemove()
- {
- }
- /**
- * Loads the state of the bean from secondary storage. Required by EJB spec.
- */
- public void ejbActivate()
- {
- }
- /**
- * Serializes the state of the bean to secondary storage. Required by EJB
- * spec.
- */
- public void ejbPassivate()
- {
- }
- // ------------------------------------------
- // 业务方法
- // ------------------------------------------
- public String runTask(String triggerId, String clazz, String inParam) throws RemoteException
- {
- TriggerTask task = null;
- try
- {
- task = (TriggerTask)Class.forName(clazz).newInstance();
- }
- catch (Exception e)
- {
- log.error("反射调用触发任务类异常", e);
- throw new RemoteException("反射调用触发任务类异常");
- }
- log.info("调用触发实现类,类名:" + clazz + ",参数:" + inParam + ",调用时间:" + new Date());
- //回调任务类,并得到运行结果
- return task.doTask(triggerId, inParam);
- }
- }
package cn.com.xinli.netb.ejb.trigger.service;
import java.rmi.RemoteException;
import java.util.Date;
import javax.ejb.SessionBean;
import org.apache.log4j.Logger;
import cn.com.xinli.netb.ejb.trigger.TriggerTask;
public class TriggerBean implements SessionBean
{
static Logger log = Logger.getLogger(TriggerBean.class);
private javax.ejb.SessionContext m_ctx = null;
/**
* Sets the session context. Required by EJB spec.
*
* @param ctx
* A SessionContext object.
*/
public void setSessionContext(javax.ejb.SessionContext ctx)
{
m_ctx = ctx;
}
/**
* Creates a bean. Required by EJB spec.
*
* @exception throws
* CreateException.
*/
public void ejbCreate() throws javax.ejb.EJBException,
javax.ejb.CreateException
{
}
/**
* Removes the bean. Required by EJB spec.
*/
public void ejbRemove()
{
}
/**
* Loads the state of the bean from secondary storage. Required by EJB spec.
*/
public void ejbActivate()
{
}
/**
* Serializes the state of the bean to secondary storage. Required by EJB
* spec.
*/
public void ejbPassivate()
{
}
// ------------------------------------------
// 业务方法
// ------------------------------------------
public String runTask(String triggerId, String clazz, String inParam) throws RemoteException
{
TriggerTask task = null;
try
{
task = (TriggerTask)Class.forName(clazz).newInstance();
}
catch (Exception e)
{
log.error("反射调用触发任务类异常", e);
throw new RemoteException("反射调用触发任务类异常");
}
log.info("调用触发实现类,类名:" + clazz + ",参数:" + inParam + ",调用时间:" + new Date());
//回调任务类,并得到运行结果
return task.doTask(triggerId, inParam);
}
}
TriggerHome.java
- package cn.com.xinli.netb.ejb.trigger.service;
- import javax.ejb.EJBHome;
- public interface TriggerHome extends EJBHome
- {
- TriggerRemote create() throws java.rmi.RemoteException, javax.ejb.CreateException;
- }
package cn.com.xinli.netb.ejb.trigger.service;
import javax.ejb.EJBHome;
public interface TriggerHome extends EJBHome
{
TriggerRemote create() throws java.rmi.RemoteException, javax.ejb.CreateException;
}
TriggerRemote.java
- package cn.com.xinli.netb.ejb.trigger.service;
- import java.rmi.RemoteException;
- import javax.ejb.EJBObject;
- public interface TriggerRemote extends EJBObject
- {
- /**
- * 调用反馈任务
- * @param triggerId 任务ID
- * @param clazz 反射类名
- * @param inParam 运行参数
- * @return
- * <li>00: 成功,触发管理器将从触发表中取消此任务</li>
- * <li>01: 失败,并触发管理器将从触发表中取消此任务</li>
- * <li>10: 成功,触发管理器在触发表中保持此任务</li>
- * <li>11: 失败,触发管理器在触发表中保持此任务</li>
- * @throws RemoteException
- */
- public String runTask(String triggerId, String clazz, String inParam) throws RemoteException;
- }
package cn.com.xinli.netb.ejb.trigger.service;
import java.rmi.RemoteException;
import javax.ejb.EJBObject;
public interface TriggerRemote extends EJBObject
{
/**
* 调用反馈任务
* @param triggerId 任务ID
* @param clazz 反射类名
* @param inParam 运行参数
* @return
* <li>00: 成功,触发管理器将从触发表中取消此任务</li>
* <li>01: 失败,并触发管理器将从触发表中取消此任务</li>
* <li>10: 成功,触发管理器在触发表中保持此任务</li>
* <li>11: 失败,触发管理器在触发表中保持此任务</li>
* @throws RemoteException
*/
public String runTask(String triggerId, String clazz, String inParam) throws RemoteException;
}
步骤3:建立 TriggerManage ,用来操作 自动任务