Quartz+Spring 实现任务监控

Quartz是一个优秀的任务调度框架,完全基于Java实现,功能强大,易于集成,最近在写了一个小项目,算是对之前接触到的技术做一个总结吧,在这个项目中使用Quartz实现对任务的监控,最终实现的效果如图:

添加效果:

目前已经实现了对Quartz任务的动态添加、暂停、恢复、删除等功能,该项目中使用的是CronTrigger,CronTrigger可以配置灵活的时间规则,是和企业级的应用。

JobDetail界面效果图:

对quartz的研究还在继续,项目也做了不少了,暂时真正研究Quartz应该算刚刚开始,还属于新人阶段,还有一些问题需要解决,在此做一个总结,同时也希望志同道合之人指点一二,互相学习,互相进步吧。

项目简介:

项目名称:cube

项目使用的服务器:tomcat

项目框架:Struts+Spring+Hibernate

数据库:Mysql

开发工具:eclipse

前端:easyui

项目模块如图:

上班族一名,只能趁工作之余来写代码,目前只是实现了系统管理和作业监控部分,系统管理整体使用Shiro实现,目前可以控制到Button级别,作业监控使用Quartz实现

Quartz中 quartz-2.1.7\quartz-2.1.7\docs\dbTables 中有我们实现监控所需的表,依照数据库选择

Quartz数据库核心表如下:

Table Name Description
QRTZ_CALENDARS 存储Quartz的Calendar信息
QRTZ_CRON_TRIGGERS 存储CronTrigger,包括Cron表达式和时区信息
QRTZ_FIRED_TRIGGERS 存储与已触发的Trigger相关的状态信息,以及相联Job的执行信息
QRTZ_PAUSED_TRIGGER_GRPS 存储已暂停的Trigger组的信息
QRTZ_SCHEDULER_STATE 存储少量的有关Scheduler的状态信息,和别的Scheduler实例
QRTZ_LOCKS 存储程序的悲观锁的信息
QRTZ_JOB_DETAILS 存储每一个已配置的Job的详细信息
QRTZ_JOB_LISTENERS 存储有关已配置的JobListener的信息
QRTZ_SIMPLE_TRIGGERS 存储简单的Trigger,包括重复次数、间隔、以及已触的次数
QRTZ_BLOG_TRIGGERS Trigger作为Blob类型存储
QRTZ_TRIGGER_LISTENERS 存储已配置的TriggerListener的信息
QRTZ_TRIGGERS 存储已配置的Trigger的信息

下面是Quartz任务监控的具体配置和实现:

Spring配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:annotation-config />
    <context:component-scan base-package="com.cube.*" />
    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="cube"></property>
        <!-- value 对应persistence.xml中的 persistence-unit name -->
    </bean>

    <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"  />
    </bean>

    <!-- login action -->

    <tx:annotation-driven transaction-manager="txManager" />

</beans>

applicationContext-quartz.xml 配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

	<bean name="quartzScheduler"
		class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="applicationContextSchedulerContextKey" value="applicationContextKey" />
		<property name="configLocation" value="classpath:quartz.properties" />
	</bean>

	<bean name="jobDetail"
		class="org.springframework.scheduling.quartz.JobDetailFactoryBean">

		<property name="jobClass">
			<value>com.cube.service.quartz.QuartzJobService</value>
		</property>
		<property name="durability" value="true" />
	</bean>

	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
		destroy-method="close">
		<property name="driverClass" value="com.mysql.jdbc.Driver" />
		<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/cube?useUnicode=true&characterEncoding=UTF8" />
		<property name="user" value="root" />
		<property name="password" value="" />
		<property name="initialPoolSize" value="10" />
		<property name="minPoolSize" value="10" />
		<property name="maxPoolSize" value="25" />
		<property name="acquireIncrement" value="5" />
		<property name="maxIdleTime" value="7200" />
	</bean>

</beans>

quartz.properties 配置

org.quartz.scheduler.instanceName = DefaultQuartzScheduler
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.wrapJobExecutionInUserTransaction = false

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true

org.quartz.jobStore.misfireThreshold = 60000

org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.isClustered = false
org.quartz.jobStore.maxMisfiresToHandleAtATime=1 

任务调度器Service

public interface SchedulerService {

    public List<Map<String, Object>> getQrtzTriggers();

    /**
     * 根据 Quartz Cron Expression 调试任务
     *
     * @param name Quartz CronTrigger名称
     * @param group Quartz CronTrigger组
     * @param cronExpression Quartz Cron 表达式,如 "0/10 * * ? * * *"等
     */
    void schedule(String name, String group, String cronExpression);

    /**
     * 根据 Quartz Cron Expression 调试任务
     *
     * @param name Quartz CronTrigger名称
     * @param group Quartz CronTrigger组
     * @param cronExpression Quartz CronExpression
     */
    void schedule(String name, String group, CronExpression cronExpression);

    /**
     *
     * @param name Quartz CronTrigger名称
     * @param group Quartz CronTrigger组
     * @param cronExpression Quartz CronExpression
     */
    void schedule(String name, String group);

    void schedule(Map<String, Object> map);

    /**
     * 暂停触发器
     *
     * @param triggerName 触发器名称
     */
    void pauseTrigger(String triggerName);

    /**
     * 暂停触发器
     *
     * @param triggerName 触发器名称
     * @param group 触发器组
     */
    void pauseTrigger(String triggerName, String group);

    /**
     * 恢复触发器
     *
     * @param triggerName 触发器名称
     */
    void resumeTrigger(String triggerName);

    /**
     * 恢复触发器
     *
     * @param triggerName 触发器名称
     * @param group 触发器组
     */
    void resumeTrigger(String triggerName, String group);

    /**
     * 删除触发器
     *
     * @param triggerName 触发器名称
     * @return
     */
    boolean removeTrigdger(String triggerName);

    /**
     * 删除触发器
     *
     * @param triggerName 触发器名称
     * @param group 触发器组
     * @return
     */
    boolean removeTrigdger(String triggerName, String group);

}

任务调度器Service实现类

@Transactional
@Service("schedulerService")
public class SchedulerServiceImpl implements SchedulerService {

    @Resource(name = "quartzDao")
    private QuartzDao quartzDao;

    @Autowired
    private Scheduler scheduler;
    @Autowired
    private JobDetail jobDetail;

    private static final String NULLSTRING = null;
    private static final Date NULLDATE = null;

    /**
     *
     * @param name
     * @param group
     * @param cronExpression
     * @see com.cube.service.SchedulerService#schedule(java.lang.String, java.lang.String,
     *      java.lang.String)
     */
    public void schedule(String name, String group, String cronExpression) {

        try {
            schedule(name, group, new CronExpression(cronExpression));

        } catch (ParseException e) {
            e.printStackTrace();
        }

    }

    /**
     * @param name
     * @param group
     * @param cronExpression
     * @see com.cube.service.SchedulerService#schedule(java.lang.String, java.lang.String,
     *      org.quartz.CronExpression)
     */
    public void schedule(String name, String group, CronExpression cronExpression) {

        if (name == null || name.trim().equals("")) {
            name = UUID.randomUUID().toString();
        }

        CronTriggerImpl trigger = new CronTriggerImpl();
        trigger.setCronExpression(cronExpression);

        TriggerKey triggerKey = new TriggerKey(name, group);

        trigger.setJobName(jobDetail.getKey().getName());
        trigger.setKey(triggerKey);

        try {
            scheduler.addJob(jobDetail, true);
            if (scheduler.checkExists(triggerKey)) {
                scheduler.rescheduleJob(triggerKey, trigger);
            } else {
                scheduler.scheduleJob(trigger);
            }
        } catch (SchedulerException e) {
            throw new IllegalArgumentException(e);
        }

    }

    /**
     * @param map
     * @see com.cube.service.SchedulerService#schedule(java.util.Map)
     */
    public void schedule(Map<String, Object> map) {
        // TODO Auto-generated method stub

    }

    /**
     * @param triggerName
     * @see com.cube.service.SchedulerService#pauseTrigger(java.lang.String)
     */
    public void pauseTrigger(String triggerName) {
        // TODO Auto-generated method stub

    }

    /**
     * @param triggerName
     * @param group
     * @see com.cube.service.SchedulerService#pauseTrigger(java.lang.String, java.lang.String)
     */
    public void pauseTrigger(String triggerName, String group) {

        try {
            scheduler.pauseTrigger(new TriggerKey(triggerName, group));
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    /**
     * @param triggerName
     * @see com.cube.service.SchedulerService#resumeTrigger(java.lang.String)
     */
    public void resumeTrigger(String triggerName) {
        // TODO Auto-generated method stub

    }

    /**
     * @param triggerName
     * @param group
     * @see com.cube.service.SchedulerService#resumeTrigger(java.lang.String, java.lang.String)
     */
    public void resumeTrigger(String triggerName, String group) {

        TriggerKey triggerKey = new TriggerKey(triggerName, group);

        try {
            scheduler.resumeTrigger(triggerKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    /**
     * @param triggerName
     * @return
     * @see com.cube.service.SchedulerService#removeTrigdger(java.lang.String)
     */
    public boolean removeTrigdger(String triggerName) {

        return removeTrigdger(triggerName, NULLSTRING);

    }

    /**
     * @param triggerName
     * @param group
     * @return
     * @see com.cube.service.SchedulerService#removeTrigdger(java.lang.String, java.lang.String)
     */
    public boolean removeTrigdger(String triggerName, String group) {

        TriggerKey triggerKey = new TriggerKey(triggerName, group);
        try {
            scheduler.pauseTrigger(triggerKey);// 停止触发器
            return scheduler.unscheduleJob(triggerKey);// 移除触发器
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @return
     * @see com.cube.service.SchedulerService#getQrtzTriggers()
     */
    public List<Map<String, Object>> getQrtzTriggers() {
        return quartzDao.getQrtzTriggers();
    }

    /**
     * @param name
     * @param group
     * @see com.cube.service.SchedulerService#schedule(java.lang.String, java.lang.String)
     */
    public void schedule(String name, String group) {

        schedule(name, group, NULLSTRING);
    }

}

QuartzDao实现

@Repository("quartzDao")
public class QuartzDao {

    private DataSource dataSource;

    @Autowired
    public void setDataSource(@Qualifier("dataSource") DataSource dataSource) {
        this.dataSource = dataSource;
    }

    // 查询Trigger
    public List<Map<String, Object>> getQrtzTriggers() {
        List<Map<String, Object>> results = getJdbcTemplate().queryForList(
                "select * from QRTZ_TRIGGERS order by start_time");
        long val = 0;
        String temp = null;
        for (Map<String, Object> map : results) {
            temp = MapUtils.getString(map, "trigger_name");
            if (StringUtils.indexOf(temp, "&") != -1) {
                map.put("display_name", StringUtils.substringBefore(temp, "&"));
            } else {
                map.put("display_name", temp);
            }

            val = MapUtils.getLongValue(map, "next_fire_time");
            if (val > 0) {
                map.put("next_fire_time", DateFormatUtils.format(val, "yyyy-MM-dd HH:mm:ss"));
            }

            val = MapUtils.getLongValue(map, "prev_fire_time");
            if (val > 0) {
                map.put("prev_fire_time", DateFormatUtils.format(val, "yyyy-MM-dd HH:mm:ss"));
            }

            val = MapUtils.getLongValue(map, "start_time");
            if (val > 0) {
                map.put("start_time", DateFormatUtils.format(val, "yyyy-MM-dd HH:mm:ss"));
            }

            val = MapUtils.getLongValue(map, "end_time");
            if (val > 0) {
                map.put("end_time", DateFormatUtils.format(val, "yyyy-MM-dd HH:mm:ss"));
            }

            map.put("trigger_state", Constant.status.get(MapUtils.getString(map, "trigger_state")));
        }

        return results;
    }

    private JdbcTemplate getJdbcTemplate() {
        return new JdbcTemplate(this.dataSource);
    }
}

JobClass

public class QuartzJobService extends QuartzJobBean {

    // 负责所有任务的调度
    private TaskService taskService;

    /**
     * @param context
     * @throws JobExecutionException
     * @see org.springframework.scheduling.quartz.QuartzJobBean#executeInternal(org.quartz.JobExecutionContext)
     */
    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {

        String triggerName = context.getTrigger().getKey().getName();

        taskService = (TaskService) getApplicationContext(context).getBean("taskService");

        taskService.execute(triggerName);

    }

    private ApplicationContext getApplicationContext(final JobExecutionContext jobexecutioncontext) {
        try {
            return (ApplicationContext) jobexecutioncontext.getScheduler().getContext()
                    .get("applicationContextKey");
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }
    }

}

TaskService所有任务的统一调用接口

public interface TaskService {

    /**
     * @param triggerName
     */
    public void execute(String triggerName);
}
@Transactional
@Service("taskService")
public class TaskServiceImpl implements TaskService {

    @Resource(name = "reportService")
    private ReportService reportService;

    /**
     * 根据TriggerName 调用不同的业务逻辑service
     *
     * @param triggerName
     * @see com.cube.service.TaskService#execute(java.lang.String)
     */
    public void execute(String triggerName) {

        if ("reportTigger".equalsIgnoreCase(triggerName)) {

            reportService.createReport();
        } else {
            System.out.println(triggerName + ":企业业务逻辑");
        }

    }

}
/**
 * 任务调度器
 *
 */
@Controller
@Scope("prototype")
public class TriggerAction extends BaseAction<TriggerEntity> {

    /**  */
    private static final long serialVersionUID = -3326354633384499660L;

    private TriggerEntity triggerEntity = getModel();

    private Map jsonMap = new HashMap();

    @Resource(name = "schedulerService")
    private SchedulerService schedulerService;

    /**
     * 跳转到tigger 管理界面
     *
     * @return
     */
    public String trigger() {

        return "trigger";
    }

    /**
     * 分页查询Trigger
     *
     * @return
     */
    public String list() {

        List<Map<String, Object>> list = schedulerService.getQrtzTriggers();

        jsonMap.put("rows", list);
        jsonMap.put("total", list.size());
        return "list";
    }

    /**
     * 添加触发器
     *
     * @return
     */
    public String save() {

        // 获取界面以参数
        String triggerName = triggerEntity.getTrigger_name();
        String cronExpression = triggerEntity.getCron();
        String group = triggerEntity.getTrigger_group();

        schedulerService.schedule(triggerName, group, cronExpression);

        jsonMap.put("flag", true);

        return "save";
    }

    /**
     * 暂停
     *
     * @return
     */
    public String pause() {

        schedulerService.pauseTrigger(triggerEntity.getTrigger_name(),
                triggerEntity.getTrigger_group());

        jsonMap.put("flag", true);

        return "pause";
    }

    /**
     * Trigger恢复
     *
     * @return
     */
    public String play() {
        schedulerService.resumeTrigger(triggerEntity.getTrigger_name(),
                triggerEntity.getTrigger_group());

        jsonMap.put("flag", true);
        return "play";
    }

    /**
     * 删除
     *
     * @return
     */
    public String deleteTrigger() {

        schedulerService.removeTrigdger(triggerEntity.getTrigger_name(),
                triggerEntity.getTrigger_group());

        jsonMap.put("flag", true);

        return "deleteTrigger";
    }

    public Map getJsonMap() {
        return jsonMap;
    }

    public void setJsonMap(Map jsonMap) {
        this.jsonMap = jsonMap;
    }

}

参考资料:

https://www.ibm.com/developerworks/cn/opensource/os-cn-quartz/

http://tech.meituan.com/mt-crm-quartz.html

时间: 2024-10-10 05:18:13

Quartz+Spring 实现任务监控的相关文章

quartz+spring 实现多任务动态定时器问题

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <beans xmlns="http://www.springframework.org/schema/beans"     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"   

quartz spring配置实例代码demo下载

原文:quartz spring配置实例代码demo下载 源代码下载地址:http://www.zuidaima.com/share/1550463459560448.htm

Spring Boot应用监控的实战教程

概述 Spring Boot 监控核心是 spring-boot-starter-actuator 依赖,增加依赖后, Spring Boot 会默认配置一些通用的监控,比如 jvm 监控.类加载.健康监控等. 我们之前讲过Docker容器的可视化监控,即监控容器的运行情况,包括 CPU使用率.内存占用.网络状况以及磁盘空间等等一系列信息.同样利用SpringBoot作为微服务单元的实例化技术选型时,我们不可避免的要面对的一个问题就是如何实时监控应用的运行状况数据,比如:健康度.运行指标.日志信

分布式调度QUARTZ+SPRING

使用SPRING的定时任务框架,如果是在分布式的环境下,由于有多台节点,会产生相同的任务,会被多个节点执行,这时需引入分布式的QUARTZ. 触发器:存放时间排程 任务:蔟业务代码 排程器:负责调度,即在指定的时间执行对应的任务 如果是分布式QUARTZ,则各个节点会上报任务,存到数据库中,执行时会从数据库中取出触发器来执行,如果触发器的名称和执行时间相同,则只有一个节点去执行此任务. 如果此节点执行失败,则此任务则会被分派到另一节点执行. quartz.properties # =======

Quartz+spring+maven集成实例(解决Job实现类注入bean为空的问题)

环境: jdk1.7.eclipse.maven.quartz2.2.1 包的架构: 流程: 1.创建项目并在pom中加入相应的jar包 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0

搭建第一个web项目:quartz+spring实现定时任务

测试过程: 先写了一个简单的任务类,测试配置的quartz是否启作用(最终目的是实现定时删除临时储存文件夹). spring中添加的配置文件如下: <!--定时任务 quartz (spring内部集成) --> <!-- 定时清空临时文件夹的任务类 --> <bean id="taskJob" class="cn.itcast.oa.util.TaskJob"></bean> <!-- 定义目标bean和bea

【59】Quartz+Spring框架详解

什么是Quartz Quartz是一个作业调度系统(a job scheduling system),Quartz不但可以集成到其他的软件系统中,而且也可以独立运行的:在本文中"job scheduler"的意思是:一个负责在约定的时间到达时执行(或通知)其他软件控件的方法. Quartz是非常灵活的,为了实现我们的需求Quartz包含了许多可以独立或被集成使用的典型范例,同时使我们编写项目中的代码也觉得很简单自然(natural). Quartz是很轻量级的,只需要简单的安装或配置就

druid+spring的url监控和spring监控开启

1,url监测: web.xml中配置以下代码: <!-- druid url monitor setting start --> <filter> <filter-name>DruidWebStatFilter</filter-name> <filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class> <init-param> <p

关于spring boot启动监控端点的方法(spring-boot-starter-actuator)

前言: 在spring boot的旧版本中,监控端点(如/env)是默认开启的,所以只要项目正常启动,就能通过url获取信息.可是在2.0版本以后,由于安全性考虑,除了/health和/info的端点,默认都是不暴露的. 那么,要怎么开启监控点呢? 启动.暴露端点的配置代码如下:(放在application.properties文件中) #--------------关于actuator暴露端点的配置(version: Spring-Boot-2.0)----------------- # 说明