Spring boot集成Quartz与RabbitMQ

activeMQ 与 quartz 事例 NULL 博文链接:https://ycljf86.iteye.com/blog/700926 立即下载

完成一个本地demo的小项目。
在Spring boot中集成Quartz与RabbitMQ,完成通过Quartz定时向RabbitMQ发送消息,并且在客户端监听RabbitMQ队列的消息并进行处理。同时针对Quartz使用了集群特性。

数据层采用Spring boot jpa,用Hibernate简易处理了下CRUD。

环境准备

  • 数据库中建立业务存储表
    t_account 账户表
    t_order 订单表
    t_order_process_detail 订单处理详情表
DROP TABLE IF EXISTS t_order;
DROP TABLE IF EXISTS t_order_process_detail;
DROP TABLE IF EXISTS t_account;

CREATE TABLE t_order(
    id int(20) NOT NULL AUTO_INCREMENT,
    account_id int(20),
    order_process_detail_id int(20),
    order_no varchar(40) NOT NULL,
    order_price decimal(10,2),
    pay_status varchar(20),
    process_status varchar(20),
    primary KEY (id)
)ENGINE=InnoDB;

CREATE TABLE t_order_process_detail(
    id int(20) NOT NULL AUTO_INCREMENT,
    detail varchar(500),
    primary KEY (id)
)ENGINE=InnoDB;

CREATE TABLE t_account(
    id int(20) NOT NULL AUTO_INCREMENT,
    name varchar(200),
    balance decimal(10,2),
    primary KEY (id)
)ENGINE=InnoDB;
  • 需要在本地,或者虚拟机中安装RabbitMQ服务器(安装过程略)

  • 为了实现Quartz的集群配置,需要在数据库中添加Quartz的存储表。建表语句可以在Quartz的jar包的docs文件下找到适合所使用数据库的sql文件。这里使用的MySQL的innodb建表语句。

DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;

CREATE TABLE QRTZ_JOB_DETAILS(
SCHED_NAME VARCHAR(120) NOT NULL,
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
JOB_CLASS_NAME VARCHAR(250) NOT NULL,
IS_DURABLE VARCHAR(1) NOT NULL,
IS_NONCONCURRENT VARCHAR(1) NOT NULL,
IS_UPDATE_DATA VARCHAR(1) NOT NULL,
REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP))
ENGINE=InnoDB;

CREATE TABLE QRTZ_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
NEXT_FIRE_TIME BIGINT(13) NULL,
PREV_FIRE_TIME BIGINT(13) NULL,
PRIORITY INTEGER NULL,
TRIGGER_STATE VARCHAR(16) NOT NULL,
TRIGGER_TYPE VARCHAR(8) NOT NULL,
START_TIME BIGINT(13) NOT NULL,
END_TIME BIGINT(13) NULL,
CALENDAR_NAME VARCHAR(200) NULL,
MISFIRE_INSTR SMALLINT(2) NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP))
ENGINE=InnoDB;

CREATE TABLE QRTZ_SIMPLE_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
REPEAT_COUNT BIGINT(7) NOT NULL,
REPEAT_INTERVAL BIGINT(12) NOT NULL,
TIMES_TRIGGERED BIGINT(10) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;

CREATE TABLE QRTZ_CRON_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
CRON_EXPRESSION VARCHAR(120) NOT NULL,
TIME_ZONE_ID VARCHAR(80),
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;

CREATE TABLE QRTZ_SIMPROP_TRIGGERS
  (          
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    STR_PROP_1 VARCHAR(512) NULL,
    STR_PROP_2 VARCHAR(512) NULL,
    STR_PROP_3 VARCHAR(512) NULL,
    INT_PROP_1 INT NULL,
    INT_PROP_2 INT NULL,
    LONG_PROP_1 BIGINT NULL,
    LONG_PROP_2 BIGINT NULL,
    DEC_PROP_1 NUMERIC(13,4) NULL,
    DEC_PROP_2 NUMERIC(13,4) NULL,
    BOOL_PROP_1 VARCHAR(1) NULL,
    BOOL_PROP_2 VARCHAR(1) NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) 
    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;

CREATE TABLE QRTZ_BLOB_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
BLOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;

CREATE TABLE QRTZ_CALENDARS (
SCHED_NAME VARCHAR(120) NOT NULL,
CALENDAR_NAME VARCHAR(200) NOT NULL,
CALENDAR BLOB NOT NULL,
PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))
ENGINE=InnoDB;

CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;

CREATE TABLE QRTZ_FIRED_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
ENTRY_ID VARCHAR(95) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
INSTANCE_NAME VARCHAR(200) NOT NULL,
FIRED_TIME BIGINT(13) NOT NULL,
SCHED_TIME BIGINT(13) NOT NULL,
PRIORITY INTEGER NOT NULL,
STATE VARCHAR(16) NOT NULL,
JOB_NAME VARCHAR(200) NULL,
JOB_GROUP VARCHAR(200) NULL,
IS_NONCONCURRENT VARCHAR(1) NULL,
REQUESTS_RECOVERY VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,ENTRY_ID))
ENGINE=InnoDB;

CREATE TABLE QRTZ_SCHEDULER_STATE (
SCHED_NAME VARCHAR(120) NOT NULL,
INSTANCE_NAME VARCHAR(200) NOT NULL,
LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
CHECKIN_INTERVAL BIGINT(13) NOT NULL,
PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))
ENGINE=InnoDB;

CREATE TABLE QRTZ_LOCKS (
SCHED_NAME VARCHAR(120) NOT NULL,
LOCK_NAME VARCHAR(40) NOT NULL,
PRIMARY KEY (SCHED_NAME,LOCK_NAME))
ENGINE=InnoDB;

CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);

CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);
CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);

CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);
CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);

commit; 

项目配置

  • maven .pom文件
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>ecloud.demo</groupId>
    <artifactId>rabbitquartz</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>rabbitquartz</name>
    <url>http://maven.apache.org</url>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.1.RELEASE</version>
        <relativePath />
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.13</version>
        </dependency>

        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.2.1</version>
        </dependency>

        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz-jobs</artifactId>
            <version>2.2.1</version>
        </dependency>

    </dependencies>
</project>
  • Spring boot的application.yml配置
server:
  port: 80

spring:
  application:
    name: rabbitquartz
  datasource:
    name: druid
    url: jdbc:mysql://localhost:3306/quartz
    username: admin
    password: admin
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 'x' FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    maxPoolPreparedStatementPerConnectionSize: 20
    filters: stat,wall,log4j
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
  rabbitmq:
    host: 192.168.200.214
    port: 5672
    username: root
    password: root
    virtual-host: /
    publisher-confirms: true
    listener:
      prefetch: 1
  jpa:
    database: MYSQL
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL5Dialect
  • Quartz的配置
    quartz.properties
#============================================================================
# Configure JobStore
# Using Spring datasource in SchedulerConfig.java
# Spring uses LocalDataSourceJobStore extension of JobStoreCMT
#============================================================================
org.quartz.jobStore.useProperties=false
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 5000
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.txIsolationLevelReadCommitted = true
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate

#============================================================================
# Configure Main Scheduler Properties
# Needed to manage cluster instances
#============================================================================
org.quartz.scheduler.instanceName = ClusterQuartz
org.quartz.scheduler.instanceId= AUTO
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.wrapJobExecutionInUserTransaction = false

#============================================================================
# Configure ThreadPool
# Can also be configured in spring configuration
#============================================================================
#org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
#org.quartz.threadPool.threadCount = 5
#org.quartz.threadPool.threadPriority = 5
#org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true

QuartzConfig.java

package ecloud.demo.rabbitquartz.config;

import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.Executor;

import javax.sql.DataSource;

import org.quartz.Scheduler;
import org.quartz.spi.JobFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

import ecloud.demo.rabbitquartz.infra.quartz.AutowiringJobFactory;
import ecloud.demo.rabbitquartz.infra.quartz.QuartzJob;

@Configuration
public class QuartzConfig {

    // TODO 多台服务器的时间同步问题

    @Autowired
    private DataSource dataSource;

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();

        factory.setSchedulerName("Cluster_Scheduler");
        factory.setDataSource(dataSource);
        factory.setApplicationContextSchedulerContextKey("applicationContext");
        factory.setTaskExecutor(schedulerThreadPool());
        factory.setTriggers(quartzTrigger().getObject());
        factory.setQuartzProperties(quartzProperties());
        factory.setJobFactory(autowiringJobFactory());
        factory.setOverwriteExistingJobs(true);
        factory.setStartupDelay(15);
        return factory;
    }

    @Bean
    public JobFactory autowiringJobFactory() {
        return new AutowiringJobFactory();
    }

    @Bean
    public Scheduler scheduler() throws Exception {
        Scheduler scheduler = schedulerFactoryBean().getScheduler();
        scheduler.start();
        return scheduler;
    }

    @Bean
    public Properties quartzProperties() throws IOException {
        PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
        propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));

        // 在quartz.properties中的属性被读取并注入后再初始化对象
        propertiesFactoryBean.afterPropertiesSet();
        return propertiesFactoryBean.getObject();
    }

    @Bean
    public JobDetailFactoryBean quartzJob() {
        JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();

        jobDetailFactoryBean.setJobClass(QuartzJob.class);
        jobDetailFactoryBean.setDurability(true);
        jobDetailFactoryBean.setGroup("order");
        jobDetailFactoryBean.setName("order_job");
        jobDetailFactoryBean.setRequestsRecovery(true);

        return jobDetailFactoryBean;
    }

    @Bean
    public CronTriggerFactoryBean quartzTrigger() {
        CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();

        cronTriggerFactoryBean.setJobDetail(quartzJob().getObject());
        cronTriggerFactoryBean.setCronExpression("0/15 * * * * ?");

        return cronTriggerFactoryBean;
    }

    @Bean
    public Executor schedulerThreadPool() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

        executor.setCorePoolSize(15);
        executor.setMaxPoolSize(25);
        executor.setQueueCapacity(100);

        return executor;
    }
}

Quartz的两个相关类
AutowiringJobFactory.java
这个类是用来为QuartzJob中的属性进行Spring IoC注入

package ecloud.demo.rabbitquartz.infra.quartz;

import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;

public class AutowiringJobFactory extends AdaptableJobFactory {

    @Autowired
    private AutowireCapableBeanFactory capableBeanFactory;

    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        Object jobInstance = super.createJobInstance(bundle);
        // IoC injection
        capableBeanFactory.autowireBean(jobInstance);
        return jobInstance;
    }
}

QuartzJob类

package ecloud.demo.rabbitquartz.infra.quartz;

import java.util.List;

import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.PersistJobDataAfterExecution;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;

import ecloud.demo.rabbitquartz.business.entity.Order;
import ecloud.demo.rabbitquartz.business.service.RabbitQuartzService;
import ecloud.demo.rabbitquartz.infra.rabbitmq.RabbitSender;

@Component
@PersistJobDataAfterExecution
// 禁止任务并发执行
@DisallowConcurrentExecution
public class QuartzJob extends QuartzJobBean {

    private final Logger logger = LoggerFactory.getLogger(QuartzJob.class);

    @Autowired
    private RabbitQuartzService rabbitQuartzService;

    @Autowired
    private RabbitSender rabbitSender;

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {

        List<Order> orderList = rabbitQuartzService.getAllOrdersToBeProcessed();

        if (orderList.size() > 0) {
            rabbitSender.send(orderList.get(0).getId());
        }

        logger.info("End quartz job \n");
    }

}
  • RabbitMQ的配置
    RabbitMQ的一部分配置包含在Spring boot的application.yml文件中

RabbitConfig.java

package ecloud.demo.rabbitquartz.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import ecloud.demo.rabbitquartz.business.service.RabbitQuartzService;

/*
 * Spring Boot中消息接受处理完后,若无异常,则由Spring Boot发送消息接受确认。
 * spring.rabbitmq.listener.prefetch控制QoS。
 */
@Configuration
@EnableRabbit
public class RabbitConfig {

    private final Logger logger = LoggerFactory.getLogger(RabbitConfig.class);

    public static final String ORDER_ROUTING_KEY = "order_key";

    public static final String ORDER_QUEUE = "order_queue";

    public static final String ORDER_EXCHANGE = "order_exchange";

    @Bean
    Queue orderQueue() {
        return new Queue(ORDER_QUEUE);
    }

    @Bean
    DirectExchange orderExchange() {
        return new DirectExchange(ORDER_EXCHANGE);
    }

    @Bean
    Binding bindingExangeQueue() {
        return BindingBuilder.bind(orderQueue()).to(orderExchange()).with(ORDER_ROUTING_KEY);
    }

    @Bean
    RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory, RabbitQuartzService rabbitQuartzService) {
        final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);

        // 发送确认的回调方法,配合rabbitmq.publisher-confirms=true
        rabbitTemplate.setConfirmCallback((correlationData, b, s) -> {
            if (b) {
                logger.info("Sending OK");
            } else {
                logger.error("Sending failed, cause: " + s);
            }
        });

        rabbitTemplate.setMessageConverter(messageConverter());

        return rabbitTemplate;
    }

    @Bean
    Jackson2JsonMessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }
}
  • Hibernate配置
    HibernateConfig.java
package ecloud.demo.rabbitquartz.config;

import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@Configuration
@EntityScan(basePackages = "ecloud.demo.rabbitquartz.business")
@EnableJpaRepositories(basePackages = "ecloud.demo.rabbitquartz.business")
public class HibernateConfig {

}

剩余的部分就是传统的Spring项目,业务层,dao层等等。
项目结构:
这里写图片描述

项目运行

复制项目后,只需要修改application.yml中的server port,就可以模拟同时启动多个服务器实例。
丰富Controller层的接口以后,可以通过postman等工具来完成订单创建等。

我们也可以观察到多个服务器同时运行模拟了一个Quartz集群,只在一个服务器中有QuartzJob的执行,并且一旦该服务器被关闭,QuartzJob可以在剩余可用的服务器中被执行。

同时观察RabbitMQ服务器,可以发现在配置的队列中(这里是order_queue),有消息的进入以及被消费。

待解决问题

在当前项目中,Quartz的集群是在同一个主机上运行的。如果服务器的示例是在不同的服务器中需要考虑服务器的时间同步。关于这一点,我还没想好。

代码下载

全部代码下载链接:
https://github.com/wanghaoalain/rabbitquartz.git

CentOS7下Node.js v20+安装与常见依赖库问题解决指南 本文详细介绍了在CentOS7系统下安装Node.js v20+的完整流程及常见依赖库问题的解决方案。通过升级glibc到2.28+、配置环境变量以及处理libstdc++版本问题,帮助开发者顺利在老旧系统上部署最新版Node.js,提升开发效率。 阅读详情

相关推荐

第四篇:关于python程序打包的问题-找不到fsspec

这个问题困扰了我将近两天的时间一直找不到什么好的办法,甚至打算放弃。主要原因是身边没有可以述说的人,也没有可以请教的人。正在想要放弃的时候找到了解决办法。 打包后运行程序是这样的, 大概意思是找不见fsspec这个依赖,刚接触python说实话对于这些第三方库理解不是很到位,我的理解就是:类似于java程序中的jar包,程序找不见了。可怎么让他找见了,刚开始以为我自己没有安装fsspec,在cmd中进行了安装,结果如下图所示 很明显,已经安装并且安装目录都有,跟着网上的一些解决办法,在打包的时候把这.

weixin_47861710的博客 5865

大数据互联网架构阶段 QuartZ定时任务+RabbitMQ消息队列

QuartZ定时任务+RabbitMQ消息队列 一 、QuartZ定时任务解决订单系统遗留问题 情景分析: 在电商项目中 , 订单生成后 , 数据库商品数量-1 , 但是用户迟迟不进行支付操作 , 这样不仅导致没有生成效益, 而且导致后来的用户无法购买的问题 。 这种情况的订单成为恶意订单 解决方案: 早期: 虚拟商品数量 , 数量减到0时 ,仍然可以减。 但是这种办法显然没有根本的...

chou_out_man的博客 1万+

Java农产品质量溯源大数据管理系统源码

产品追溯基于“一物一码”从工厂生产环节至销售阶段,赋予产品唯一的数码,并关联产品名称、批号、生产时间等信息,建立包装关联关系,为后期产品的追溯、营销搭建信息基础。 农产品溯源,从原材料收购、生产、加工质检到包装运输、终端门店销售等环节追溯,可以保证产品质量,监管部门和消费者都可以查询产品信息。对生产进行层层把关、一旦发现问题、立即进行处理、提升产品质量。

xingchen优快云的博客 1805

超详细的RabbitMQ笔记

详细介绍RabbitMQ,从概念到安装到玩转,细节满满,带你轻松上手MQ

m0_64416017的博客 269

DFT设计绪论

DFT设计的主要目的是为了将defect-free的芯片交给客户。 产品质量,通常使用Parts Per million(PPM)来衡量。 但是随着IC从SSI到VLSI的发展,在test上花销的时间越来越多,test的quality却很难提高,这使得DFT的engineer不断的发展着DFT的技术。 DFT engineer面对的第一个问题是设计内部的状态的可测试性问题。在...

ahr7882的博客 1195

基于STM32的智能火灾报警系统设计:多传感器融合与远程控制实现

本文详细介绍基于STM32单片机的智能火灾报警系统设计,采用多传感器融合技术(烟雾、温度、火焰检测)实现高精度火灾识别。系统集成远程控制与手机APP监控,通过加权决策算法降低误报率,提供多级响应策略,确保火灾预警的准确性与可靠性。

u5v6w7的博客 1103

[中间件] RabbitMQ 的 Exchange 和 Queue 绑定:实现高效消息传递的关键步骤

Exchange 和 Queue 绑定是 RabbitMQ 中实现消息路由的关键步骤。通过为 Exchange 和 Queue 建立绑定关系,我们可以确保消息能够被准确路由到对应的消费者,从而实现精确的消息传递。在 Spring Boot 中,我们可以通过配置文件或配置类的方式来进行 Exchange 和 Queue 的绑定,从而实现消息的传递。

2301_79528833的博客 2795

ROS教程(四):RVIZ使用教程(详细图文)

前言 根据前面的教程已经学会了创建功能包,那么本篇文章主要内容则是通过节点来发布数据至RVIZ

Leslie的博客 17万+

RabbitMQ + Quartz +Swagger 使用记录

1、RabbitMQ概述 1、官方解释 RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件)。RabbitMQ服务器是用Erlang语言编写的,而群集和故障转移是构建在开放电信平台框架上的。所有主要的编程语言均有与代理接口通讯的客户端库。 Erlang是一种通用的面向并发的编程语言,它由瑞典电信设备制造商爱立信所辖的CS-Lab开发,目的是创造一种可以应对...

weixin_33755847的博客 558

CMOS图像传感器系列--(四)HDR之LOFIC技术

CMOS图像传感器HDR技术之LOFIC解析 LOFIC(横向溢出积分电容器)技术是当前高动态范围成像的重要方案,通过在像素光电二极管旁设置高密度电容器收集溢出电荷,有效保留高光细节。该技术采用特殊像素结构,通过skim level触发电荷转移,实现单帧HDR成像。然而LOFIC存在显著局限性:高光区域噪声明显且难以消除,动态范围拓展不均衡(主要优化亮部),需复杂MIM工艺导致成本升高。为应对挑战,行业提出混合方案(如结合DCG技术)和工艺改进方向。OmniVision最新车载传感器OX08D10就采用了L

AIoT深度探索者 | 嵌入式系统架构师 深耕物联网(IoT)与人工智能(AI)融合技术,聚焦​​边缘计算、图像开发、低功耗通信协议​​,致力于智能硬件,关注我获取最新技术文章信息与海量资源~ 5799

Coze智能体实战:接口需求分析和接口调试

AI智能体的需求:能根据接口文档提取接口信息以及设计接口测试点,并进行接口调试返回接口测试结果。

十二测试录 283

RabbitMQ

我们为什么需要rabbitmq

m0_72710328的博客 192

[DDR5]DDR5 SDRAM 状态图 和 基本功能

DDR5 SDRAM的读写操作以突发(burst mode)为导向,从选定的位置开始,并按照编程顺序进行16个突发长度或8个“切片”突发长度的操作。从ACTIVATE命令开始,然后是读取或写入命令。

串起点滴 1201

基于Spring Boot的医疗设备维护平台

Java领域优质创作者🏆、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行交流合作。

2301_79727522的博客 690

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Spring 5.2.8测试依赖汇总

<?xml version="1.0" encoding="UTF-8"?> <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 https://maven.apache.org/xsd/maven-4.0.0

m0_37607945的博客 535

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

SpringBoot所有的Starter以及常用依赖

官网 官网 列表 spring-boot-starter Core starter, including auto-configuration support, logging and YAML spring-boot-starter-activemq Starter for JMS messaging using Apache ActiveMQ spring-boot-starter-amqp Starter for using Spring AMQP and Rabbit MQ

A_java_c的博客 2052

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Spring Boot 企业级开发

《Spring Boot企业级开发教程(第2版)》 黑马程序员 著

weixin_67145605的博客 1389

3步跑通芋道源码框架:Spring Boot企业级开发的完整答案

每次新项目立项,你是不是又要在登录、权限、菜单、角色这些"老面孔"上重写一遍?业务还没开始,地基先打了一个月。**芋道源码(ruoyi-spring-boot-all)** 就是一个基于 Spring Boot 的开源企业级后台开发框架,把权限、工作流、电商、支付等高频能力打包成"开箱即用"的模块矩阵,让你把精力从"造轮子"挪回"做业务"。 ## 开篇一问:你的时间,是不是都耗在了重复造轮子上?

gitblog_01058的博客 188

springboot信用卡管理系统设计开发实现

Spring Boot信用卡管理系统通过技术标准化、业务模块化、数据资产化,解决了传统管理的痛点,同时为金融创新(如虚拟信用卡、区块链征信)预留扩展空间,具有显著的商业价值和社会效益。

2501_93250029的博客 269

springboot继承组件_GitHub - superleeyom/spring-boot-learning: Spring Boot 学习笔记,Spring Boot 与各种其他技术或者组件的集...

目录Spring Boot 集成测试和部署运维测试用的类,需要在类的头部添加 @RunWith(SpringRunner.class) 和 @SpringBootTest 注解。@RunWith(SpringRunner.class)@SpringBootTestpublic class TestUserService {}测试常用的注解和类:@Test:Junit 常用注解...

weixin_42600407的博客 579

基于springboot的工业生产计划管理系统设计实现

在制造业数字化转型浪潮下,传统的生产计划管理方式(如Excel表格、纸质单据)已难以满足现代企业对于生产敏捷性、资源优化和实时决策的需求。生产计划作为连接销售、采购、库存与车间执行的枢纽,其管理效率直接影响到订单交付周期、生产成本与客户满意度。本系统采用前后端分离的微服务架构,后端基于SpringBoot生态,前端采用现代Vue.js框架,确保系统的高性能、可维护性与可扩展性。核心算法服务,根据MPS、BOM和库存计算物料净需求。核心服务类,负责基于销售订单和预测生成主生产计划。

java python定制开发 189

Spring Boot 实现延时任务的 4 种方式:Redis、RabbitMQ、Quartz、时间轮对比

七、总结与实践建议简单场景(如订单取消):推荐 Redis ZSet,实现快,依赖轻高并发场景(消息延迟):推荐 RabbitMQ/Kafka 延时队列复杂调度任务(多任务依赖、分布式调度):选择 Quartz + DB高性能定时器(游戏、缓存刷新):可用 时间轮在实际开发中,可以根据 任务可靠性、并发量、可维护性 来选择合适的方案。四、基于 Quartz 的延时任务1. 思路Quartz 是专业的任务调度框架,支持 CRON 表达式、持久化、分布式,适合复杂的调度任务。// 消费任务(定时扫描)

nihao2q的博客 1277

Spring Boot核心依赖解析与最佳实践

Spring Boot作为Java领域主流的开发框架,其starter机制通过依赖管理自动化显著提升了开发效率。理解Maven依赖管理原理是掌握现代Java开发的基础,Spring Boot将常用功能封装成starter模块,如spring-boot-starter-web整合了Tomcat、Spring MVC等组件。这种设计在微服务架构中尤为重要,能快速构建RESTful API或实现Redis缓存集成。实际开发中,合理选择starter组合(如web+data-jpa+security)可避免依赖冲突

weixin_33933118的博客 388

使用Spring Boot集成中间件:基础篇

Spring Boot是一个非常流行的Java开发框架,它提供了许多常用的中间件和技术栈集成。下面是一些常用的中间件和技术栈,可以与Spring Boot一起使用:

m0_68856746的博客 2565
上一篇: Spring Boot与Quartz集成实现分布式定时任务集群
下一篇: Centos 7_MySQL主主复制_Haproxy实现负载均衡
AlainGogogo
博客等级 码龄18年 5粉丝 20原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值