Maison  >  Article  >  Java  >  springboot+quartz implémente les tâches planifiées de manière persistante

springboot+quartz implémente les tâches planifiées de manière persistante

Guanhui
Guanhuiavant
2020-07-27 18:33:192950parcourir

springboot+quartz implémente les tâches planifiées de manière persistante

Cet article présente springboot+quartz pour implémenter des tâches planifiées de manière persistante. Les détails sont les suivants :

C'est assez long, mais ceux qui sont patients peuvent. toujours Après avoir obtenu la réponse finale, c'est la première fois que j'utilise du quartz pour effectuer une tâche planifiée, je m'excuse pour toute lacune.

Tout d'abord

Il est relativement simple d'effectuer des tâches planifiées dans le projet Springboot. Le moyen le plus simple de l'implémenter est d'utiliser le. **Annotation @Scheduled. Utilisez ensuite @EnableScheduling** sur la classe de démarrage de l'application pour activer les tâches planifiées.

Exemple

@SpringBootApplication
@EnableScheduling
public class Application {

 public static void main(String[] args) {
 SpringApplication.run(Application.class, args);
 }
 // cron为每秒执行一次
 @Scheduled(cron = "* * * * * ?")
 public void print(){
 System.out.println("执行定时任务");
 }

}

######Résultat

Exécuter la tâche planifiée
Exécuter la tâche planifiée
Exécuter la tâche planifiée
Exécuter la tâche planifiée task Tâche
Exécuter une tâche planifiée
Exécuter une tâche planifiée
Exécuter une tâche planifiée
Exécuter une tâche planifiée

Des tâches planifiées simples peuvent être effectuées de cette manière, cron expression Le résultat est l'intervalle entre les exécutions de tâches.

Cependant,

Dans le développement réel, nous pouvons avoir de nombreuses tâches et devoir exécuter manuellement des tâches individuelles/toutes, telles que l'ajout, l'ouverture , arrêter, continuer et d'autres opérations. Ensuite, le quartz apparaîtra avec le BGM de "Qianniu Class B...".

quartz

Intégrer les trois éléments de

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

quartz

  • Scheduler
  • Démarrer le déclencheur pour exécuter la tâche
  • Trigger Trigger

est utilisé pour définir les conditions de déclenchement du travail (tâche), l'heure de déclenchement, l'intervalle de déclenchement, l'heure de fin, etc.

Tâche de travail

Contenu de la tâche spécifique à effectuer

Utilisation

L'utilisation de quartz nécessite un fichier de configuration. Le fichier de configuration par défaut quartz.properties se trouve sous le package org.quartz du package quartz jar quartz.properties

# Default Properties file for use by StdSchedulerFactory
# to create a Quartz Scheduler Instance, if a different
# properties file is not explicitly specified.
#
# 名字
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
# 实例化ThreadPool时,使用的线程类为SimpleThreadPool
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
# 持久化方式,默认持久化在内存中,后面我们使用db的方式
org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore

Les tâches de quartz persistantes pour la base de données nécessitent certaines bases de données officiellement définies. Table, le fichier sql de la table se trouve dans le package jar de quartz

coordonnées org.quartz.impl.jdbcjobstore Vous pouvez voir qu'il contient de nombreux fichiers sql, y compris diverses bases de données que nous utilisons. MySQL Il n'est pas nécessaire d'exécuter manuellement l'instruction sql, nous l'initialiserons automatiquement plus tard lors du démarrage du projet.

Créez notre propre fichier de propriétés

# 实例化ThreadPool时,使用的线程类为SimpleThreadPool
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
# threadCount和threadPriority将以setter的形式注入ThreadPool实例
# 并发个数
org.quartz.threadPool.threadCount=10
# 优先级
org.quartz.threadPool.threadPriority=5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true
org.quartz.jobStore.misfireThreshold=5000
#持久化使用的类
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
#数据库中表的前缀
org.quartz.jobStore.tablePrefix=QRTZ_
#数据源命名
org.quartz.jobStore.dataSource=qzDS
#qzDS 数据源,我们使用hikaricp,默认的是c3p0
org.quartz.dataSource.qzDS.provider=hikaricp
org.quartz.dataSource.qzDS.driver=com.mysql.cj.jdbc.Driver
org.quartz.dataSource.qzDS.URL=jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
org.quartz.dataSource.qzDS.user=root
org.quartz.dataSource.qzDS.password=123456
org.quartz.dataSource.qzDS.maxConnections=10

Puisque nous n'utilisons pas le pool de connexions par défaut, explorons-le et récupérons le code source ! Sous ce package : org.quartz.utils, il y a un PoolingConnectionProvider. Comme son nom l'indique, le code source de la partie du fournisseur de pool de connexions

public interface PoolingConnectionProvider extends ConnectionProvider {

 /** The pooling provider. */
 String POOLING_PROVIDER = "provider";

 /** The c3p0 pooling provider. */
 String POOLING_PROVIDER_C3P0 = "c3p0";

 /** The Hikari pooling provider. */
 String POOLING_PROVIDER_HIKARICP = "hikaricp";

}

Ensuite, la classe HikariCpPoolingConnectionProvider implémente PoolingConnectionProvider, vérifiez-le vous-même. Nous pouvons rechercher c3p0 dans StdSchedulerFactory sous org.quartz.impl pour trouver

if(poolingProvider != null && poolingProvider.equals(PoolingConnectionProvider.POOLING_PROVIDER_HIKARICP)) {
  cpClass = "org.quartz.utils.HikariCpPoolingConnectionProvider";
  }
  else {
  cpClass = "org.quartz.utils.C3p0PoolingConnectionProvider";
  }

Jetons un coup d'œil au reste. La recherche du code source de départ n'est pas aussi difficile ou ennuyeuse qu'on l'imagine (je n'aime pas le faire. lisez le code source non plus) ), mais ce code source semble avoir un petit sentiment d'accomplissement.

Retournez au canal thématique et configurez application.yml

spring:
 datasource:
 driver-class-name: com.mysql.cj.jdbc.Driver
 password: 123456
 url: jdbc:mysql://localhost:3306/quartz?characterEncoding=UTF8&useSSL=false&serverTimezone=GMT%2B8
 username: root
 quartz:
 jdbc:
 initialize-schema: always
 job-store-type: jdbc

initialize-schema : toujours Chaque fois que vous démarrez le projet, initialisez toujours la table de la base de données et créez automatiquement la partie clé de la table . Le processus consiste à supprimer d'abord la table de la base de données, puis à la créer à nouveau. Si la table n'existe pas, une exception sera levée, mais elle n'affectera pas la table générée ultérieurement lors du prochain démarrage du projet, car la table est déjà créée. existe, l'exception ne sera pas levée job-store-type : jdbc C'est le type de persistance de la tâche. Nous utilisons jdbc

Nous devrons peut-être injecter des objets spring dans le travail, il ne peut pas être injecté. .

/**
 * @author: taoym
 * @date: 2020/6/4 11:32
 * @desc: 一定要自定义JobFactory重写SpringBeanJobFactory的createJobInstance方法,否则在job中是获取不到spring容器中的bean的
 */
@Component
public class JobFactory extends SpringBeanJobFactory {

 @Autowired
 private AutowireCapableBeanFactory beanFactory;

 /**
 * 这里覆盖了super的createJobInstance方法,对其创建出来的类再进行autowire
 */
 @Override
 protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
 Object jobInstance = super.createJobInstance(bundle);
 beanFactory.autowireBean(jobInstance);
 return jobInstance;
 }
}

Créer un fichier de configuration quartz

@Configuration
public class QuartzConfig {

 @Autowired
 private JobFactory jobFactory;

 /**
 * 读取quartz.properties 文件
 * 将值初始化
 *
 * @return
 */
 @Bean
 public Properties quartzProperties() throws IOException {
 PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
 propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
 propertiesFactoryBean.afterPropertiesSet();
 return propertiesFactoryBean.getObject();
 }

 @Bean
 public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
 SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
 schedulerFactoryBean.setJobFactory(jobFactory);
 schedulerFactoryBean.setQuartzProperties(quartzProperties());
 return schedulerFactoryBean;
 }

 /**
 * 初始化监听器
 *
 * @return
 */
 @Bean
 public QuartzInitializerListener executorListener() {
 return new QuartzInitializerListener();
 }


 @Bean(name = "scheduler")
 public Scheduler scheduler() throws IOException {
 return schedulerFactoryBean().getScheduler();
 }
}

Créer un composant de déclenchement

public class TriggerComponent {

 /**
 * @author: taoym
 * @date: 2020/6/1 10:35
 * @desc: 构建cron触发器
 */
 public static Trigger cronTrigger(String cron) {
 CronTrigger cronTrigger = TriggerBuilder.newTrigger()
 .withSchedule(CronScheduleBuilder.cronSchedule(cron).withMisfireHandlingInstructionDoNothing())
 .build();
 return cronTrigger;
 }

 public static Trigger cronTrigger(String cron, JobDataMap jobDataMap) {
 CronTrigger cronTrigger = TriggerBuilder.newTrigger()
 .withSchedule(CronScheduleBuilder.cronSchedule(cron).withMisfireHandlingInstructionDoNothing())
 .usingJobData(jobDataMap)
 .build();
 return cronTrigger;
 }
}

Utilisez simplement ce composant pour obtenir le déclencheur.

Créer une tâche

@DisallowConcurrentExecution
public class TestJob extends QuartzJobBean {
 @Override
 protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
 
 }
}

jobExecutionContext Ici, vous pouvez obtenir le groupe de tâches, le nom de la tâche, le groupe de déclencheurs, le nom du déclencheur, les détails de la tâche et d'autres informations. Cette annotation vise à permettre à la même instance (jobdetail) d'être exécutée uniquement dans un seul thread. On peut comprendre que job est l'interface, jobdetail est la classe d'implémentation et a est l'une des classes d'implémentation. Il faut 100 secondes pour effectuer une certaine opération, et le minuteur que vous avez donné effectuera une opération toutes les 50 secondes. via l'exécution Un autre thread doit être démarré pour l'exécution. L'utilisation de DisallowConcurrentExecution signifie que lorsque a n'a pas terminé l'opération, a n'est pas autorisé à démarrer le thread puis à effectuer l'opération en cours. Je ne sais pas si ma description est facile à comprendre !

Créez votre propre liste de tâches selon vos besoins. J'utilise des tâches planifiées pour créer des robots (petits robots)

CREATE TABLE `quartz_job` (
 `id` int(11) NOT NULL AUTO_INCREMENT COMMENT &#39;编号&#39;,
 `job_name` varchar(50) DEFAULT &#39;&#39; COMMENT &#39;任务名&#39;,
 `job_group` varchar(50) DEFAULT &#39;&#39; COMMENT &#39;任务组名称&#39;,
 `job_desc` varchar(255) DEFAULT &#39;&#39; COMMENT &#39;job描述&#39;,
 `cron` varchar(50) DEFAULT &#39;&#39; COMMENT &#39;cron表达式&#39;,
 `status` tinyint(1) DEFAULT &#39;0&#39; COMMENT &#39;状态&#39;,
 `url` varchar(255) DEFAULT &#39;&#39; COMMENT &#39;请求地址&#39;,
 `param` varchar(255) DEFAULT &#39;&#39; COMMENT &#39;参数&#39;,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8;

Lorsque nous ajoutons des tâches, nous ne traitons pas de quartz, mettons simplement les tâches dedans. la base de données. Pas de panique, il vous sera utile plus tard. Ce tableau doit être ajouté, supprimé, modifié et vérifié. Nous allons interroger la liste des tâches dans le système et sélectionner une ou toutes les tâches pour commencer à exécuter

Exécuter la tâche

@Resource
 private QuartzJobMapper quartzJobMapper;
 @Autowired
 private Scheduler scheduler;
 
 
 @Override
 public String start(Integer id) {
 
		JobDataMap jobDataMap = new JobDataMap();
 jobDataMap.put(k,v);
 
 QuartzJob quartzJob = quartzJobMapper.selectByPrimaryKey(id);
 
 JobKey jobKey = JobKey.jobKey(quartzJob.getJobName(), quartzJob.getJobGroup());
 
 jobDetail = JobBuilder.newJob(TestJob.class).withIdentity(jobKey).storeDurably().build();
 
 Trigger trigger = TriggerComponent.cronTrigger(quartzJob.getCron(), jobDataMap);
 try {
 scheduler.scheduleJob(jobDetail, trigger);
 quartzJobMapper.updateStatus(true, id);
 return "开始任务执行成功";
 } catch (SchedulerException se) {
 log.info("开始任务的时候发生了错误");
 }
 return "开始任务的时候发生了错误,请检查日志";
 }

Enfin, Je l'ai collé selon le contenu de ce tutoriel. Une fois le code passé, il peut fonctionner normalement.

Tutoriel recommandé : "PHP"

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer