暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Spring boot + Quartz-JDBC 动态CRUD(增删改查)

Java架构师编程 2018-07-15
913

提醒:以下有代码示例,建议浏览器打开,或者手机横屏阅读,避免影响阅读体验。


以前介绍过quartz 的入门使用,当时使用的RAMJobStore 存储方式,这是基于内存 存储Job的相关信息,比如cronExpression 等信息。

这时,当我们重启软、硬件服务时,会导致内存中的数据丢失。也会导致正在执行的job,被强行中断,比如一个job需要执行15分钟,我在第10分钟的时候,重启服务了。那,在服务启动后,该job,已产生的数据,该如何处理?是等下次job再次执行,重新更新,还是立即重新执行??这些都不确定, 会带来一系列麻烦的问题。

今天要说的解决方案就是: 基于JDBCJobStore 实现Job 的动态CRUD。

这里是官方文档http://www.quartz-scheduler.org/documentation/quartz-2.1.x/tutorials/tutorial-lesson-09.html

在JDBCJobStore 模块下介绍了其几个配置的关键点,可先了解一下,再看下文实现过程。

惯例,我们使用Spring boot,构建一个Srping mvc服务,

1.  加上quartz 的依赖

<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>

2. 添加quartz.properties : 在 application.properties 平级目录下,新增 quartz.properties 文件,添加如下配置:

# quartz begin

# JobStoreCMT用来适配Spring 等事务管理。JobStoreTX quartz自己的事务管理, 但这样理解,好像也不对啊

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.dataSource = my_quartz_datasource

org.quartz.jobStore.useProperties = true

# 实例化ThreadPool时,使用的线程类为SimpleThreadPool

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool

# threadCountthreadPriority将以setter的形式注入ThreadPool实例

# 并发个数

org.quartz.threadPool.threadCount = 5

# 优先级

org.quartz.threadPool.threadPriority = 5

org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true

org.quartz.jobStore.misfireThreshold = 5000

#==============================================================

#Configure DataSource

#==============================================================

org.quartz.dataSource.my_quartz_datasource.driver = com.mysql.jdbc.Driver

org.quartz.dataSource.my_quartz_datasource.URL = jdbc:mysql://localhost:33306/s_web?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8

org.quartz.dataSource.my_quartz_datasource.user = root

org.quartz.dataSource.my_quartz_datasource.password = _hx7h82gfc28c250n

org.quartz.dataSource.my_quartz_datasource.maxConnections = 30

# quartz end

3. 在mysql 数据库中,建立相关表单,http://www.quartz-scheduler.org/downloads/ 下载quartz的安装包,在docs/dbTables 中,找到相应的sql,我使用的是mysql,选择了tables_mysql_innodb.sql,注意,表的前缀,与properties中配置一致,在mysql 中执行sql 语句,建表。

4. spring boot 中,添加shedule相关bean 的配置:

自定义工厂类:

/**

* Created on 2018-07-15

* @author tangyuan

*/

@Component

public class MyJobFactory extends AdaptableJobFactory {

   @Autowired

   private AutowireCapableBeanFactory capableBeanFactory;

   @Override

   protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {

       Object jobInstance = super.createJobInstance(bundle);

       capableBeanFactory.autowireBean(jobInstance); //这一步解决不能spring注入bean的问题

       return jobInstance;

   }

新建ConfigBeans.java  进行相关bean 注入

@Configuration

public class ConfigBeans {

   @Autowired

   private MyJobFactory myJobFactory;  //自定义的factory

//获取工厂bean

@Bean

public SchedulerFactoryBean schedulerFactoryBean() {

   SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();

   try {

       schedulerFactoryBean.setQuartzProperties(quartzProperties());

       schedulerFactoryBean.setJobFactory(myJobFactory);

   } catch (IOException e) {

       e.printStackTrace();

   }

   return schedulerFactoryBean;

}

//指定quartz.properties

@Bean

public Properties quartzProperties() throws IOException {

   PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();

   propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));

   propertiesFactoryBean.afterPropertiesSet();

   return propertiesFactoryBean.getObject();

}

//quartz初始化监听器,监听器可以监听到工程的启动,在工程停止再启动时可以让已有的

// 定时任务继续进行。 注意:还是依托于spring 容器。当spring mvc 重启时,quartz 正在执行的job依旧会被中断。

@Bean

public QuartzInitializerListener executorListener() {

   return new QuartzInitializerListener();

}

//创建schedule

@Bean(name = "scheduler")

public Scheduler scheduler() {

   return schedulerFactoryBean().getScheduler();

}

}

5. 构建一个job

/**

* Created on 2018-07-15

* @author tangyuan

*/

public class TestJob  implements Job {

   private static Logger logger = LoggerFactory.getLogger(HelloJob.class);

   public TestJob() {

   }

   public void execute(JobExecutionContext context) {

       logger.info("TestJob 执行时间: " + new Date());

   }

}

6. 构建Controller,用于CRUD job, 这里只写了一个add,用于示例。如下 api,我们将 新增job 的类全路径,,及其他参数,传入。使用类全路径,实例化这个class对象。 quartz 在接收到这些参数后,会自动根据在quartz.properties 中配置的数据源,表信息,进行表的插入等操作,并开启执行job。随后,可在控制台,看到每隔10秒,job输出其执行时间。

http://localhost:8080/addjob?jobClassName=com.***.web.job.NewJob&jobName=NewJob&groupName=group1

/**

* Created on 2018-07-15

* @author tangyuan

*/

@Controller

public class QuartzJobController {

   @ResponseBody

   @RequestMapping(value="/addjob")

   public void addjob(@RequestParam(value="jobClassName")String jobClassName,

                      @RequestParam(value = "jobName") String jobName,

                      @RequestParam(value = "groupName") String groupName

                      ) throws Exception

   {

       // 通过SchedulerFactory获取一个调度器实例

       SchedulerFactory sf = new StdSchedulerFactory();

       Scheduler sched = sf.getScheduler();

       // 启动调度器

       sched.start();

//使用类全路径,实例化这个class对象。

       Class newClass = Class.forName(jobClassName);

       JobDetail job = newJob(newClass).withIdentity(jobName, groupName).build();

       Trigger trigger = newTrigger().withIdentity(jobName, groupName).startNow().withSchedule(simpleSchedule()

               .withIntervalInSeconds(10)

               .repeatForever()).build();

       sched.scheduleJob(job, trigger);

   }

}

文章转载自Java架构师编程,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论