Update README.md

This commit is contained in:
johnA1331
2019-10-30 22:12:05 +08:00
committed by GitHub
parent db85c8f275
commit 33998bdac8
20533 changed files with 1642695 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
*.iml
.idea
target/
+25
View File
@@ -0,0 +1,25 @@
## Spring Quartz
This module contains articles about Spring with Quartz
### Relevant Articles:
- [Scheduling in Spring with Quartz](https://www.baeldung.com/spring-quartz-schedule)
## #Scheduling in Spring with Quartz Example Project
This is the first example where we configure a basic scheduler.
##### Spring boot application, Main class
`org.baeldung.springquartz.SpringQuartzApp`
##### Configuration in *application.properties*
- Default: configures scheduler using Spring convenience classes:
`using.spring.schedulerFactory=true`
- To configure scheduler using Quartz API:
`using.spring.schedulerFactory=false`
+61
View File
@@ -0,0 +1,61 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung</groupId>
<artifactId>spring-quartz</artifactId>
<name>spring-quartz</name>
<version>0.0.1-SNAPSHOT</version>
<description>Demo project for Scheduling in Spring with Quartz</description>
<packaging>jar</packaging>
<parent>
<artifactId>parent-boot-2</artifactId>
<groupId>com.baeldung</groupId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../parent-boot-2</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- spring's support for quartz -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<!-- quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>${quartz.version}</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>${c3p0.version}</version>
</dependency>
<!-- h2 in-memory database -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
<properties>
<quartz.version>2.3.0</quartz.version>
<c3p0.version>0.9.5.2</c3p0.version>
</properties>
</project>
@@ -0,0 +1,15 @@
package org.baeldung.springquartz;
import org.springframework.boot.Banner.Mode;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;
@ComponentScan
@EnableScheduling
public class SpringQuartzApp {
public static void main(String[] args) {
new SpringApplicationBuilder(SpringQuartzApp.class).bannerMode(Mode.OFF).run(args);
}
}
@@ -0,0 +1,90 @@
package org.baeldung.springquartz.basics.scheduler;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
import static org.quartz.TriggerBuilder.newTrigger;
import java.io.IOException;
import javax.annotation.PostConstruct;
import org.baeldung.springquartz.config.AutoWiringSpringBeanJobFactory;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
import java.util.Properties;
@Configuration
@ConditionalOnExpression("'${using.spring.schedulerFactory}'=='false'")
public class QrtzScheduler {
Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private ApplicationContext applicationContext;
@PostConstruct
public void init() {
logger.info("Hello world from Quartz...");
}
@Bean
public SpringBeanJobFactory springBeanJobFactory() {
AutoWiringSpringBeanJobFactory jobFactory = new AutoWiringSpringBeanJobFactory();
logger.debug("Configuring Job factory");
jobFactory.setApplicationContext(applicationContext);
return jobFactory;
}
@Bean
public Scheduler scheduler(Trigger trigger, JobDetail job, SchedulerFactoryBean factory) throws SchedulerException {
logger.debug("Getting a handle to the Scheduler");
Scheduler scheduler = factory.getScheduler();
scheduler.scheduleJob(job, trigger);
logger.debug("Starting Scheduler threads");
scheduler.start();
return scheduler;
}
@Bean
public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setJobFactory(springBeanJobFactory());
factory.setQuartzProperties(quartzProperties());
return factory;
}
public Properties quartzProperties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
@Bean
public JobDetail jobDetail() {
return newJob().ofType(SampleJob.class).storeDurably().withIdentity(JobKey.jobKey("Qrtz_Job_Detail")).withDescription("Invoke Sample Job service...").build();
}
@Bean
public Trigger trigger(JobDetail job) {
int frequencyInSec = 10;
logger.info("Configuring trigger to fire every {} seconds", frequencyInSec);
return newTrigger().forJob(job).withIdentity(TriggerKey.triggerKey("Qrtz_Trigger")).withDescription("Sample trigger").withSchedule(simpleSchedule().withIntervalInSeconds(frequencyInSec).repeatForever()).build();
}
}
@@ -0,0 +1,28 @@
package org.baeldung.springquartz.basics.scheduler;
import org.baeldung.springquartz.basics.service.SampleJobService;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class SampleJob implements Job {
Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private SampleJobService jobService;
public void execute(JobExecutionContext context) throws JobExecutionException {
logger.info("Job ** {} ** fired @ {}", context.getJobDetail().getKey().getName(), context.getFireTime());
jobService.executeSampleJob();
logger.info("Next job scheduled @ {}", context.getNextFireTime());
}
}
@@ -0,0 +1,101 @@
package org.baeldung.springquartz.basics.scheduler;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import org.baeldung.springquartz.config.AutoWiringSpringBeanJobFactory;
import org.quartz.JobDetail;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.quartz.QuartzDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
@Configuration
@EnableAutoConfiguration
@ConditionalOnExpression("'${using.spring.schedulerFactory}'=='true'")
public class SpringQrtzScheduler {
Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private ApplicationContext applicationContext;
@PostConstruct
public void init() {
logger.info("Hello world from Spring...");
}
@Bean
public SpringBeanJobFactory springBeanJobFactory() {
AutoWiringSpringBeanJobFactory jobFactory = new AutoWiringSpringBeanJobFactory();
logger.debug("Configuring Job factory");
jobFactory.setApplicationContext(applicationContext);
return jobFactory;
}
@Bean
public SchedulerFactoryBean scheduler(Trigger trigger, JobDetail job, DataSource quartzDataSource) {
SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();
schedulerFactory.setConfigLocation(new ClassPathResource("quartz.properties"));
logger.debug("Setting the Scheduler up");
schedulerFactory.setJobFactory(springBeanJobFactory());
schedulerFactory.setJobDetails(job);
schedulerFactory.setTriggers(trigger);
// Comment the following line to use the default Quartz job store.
schedulerFactory.setDataSource(quartzDataSource);
return schedulerFactory;
}
@Bean
public JobDetailFactoryBean jobDetail() {
JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean();
jobDetailFactory.setJobClass(SampleJob.class);
jobDetailFactory.setName("Qrtz_Job_Detail");
jobDetailFactory.setDescription("Invoke Sample Job service...");
jobDetailFactory.setDurability(true);
return jobDetailFactory;
}
@Bean
public SimpleTriggerFactoryBean trigger(JobDetail job) {
SimpleTriggerFactoryBean trigger = new SimpleTriggerFactoryBean();
trigger.setJobDetail(job);
int frequencyInSec = 10;
logger.info("Configuring trigger to fire every {} seconds", frequencyInSec);
trigger.setRepeatInterval(frequencyInSec * 1000);
trigger.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
trigger.setName("Qrtz_Trigger");
return trigger;
}
@Bean
@QuartzDataSource
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource quartzDataSource() {
return DataSourceBuilder.create().build();
}
}
@@ -0,0 +1,34 @@
package org.baeldung.springquartz.basics.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.util.concurrent.atomic.AtomicInteger;
@Service
public class SampleJobService {
public static final long EXECUTION_TIME = 5000L;
private Logger logger = LoggerFactory.getLogger(getClass());
private AtomicInteger count = new AtomicInteger();
public void executeSampleJob() {
logger.info("The sample job has begun...");
try {
Thread.sleep(EXECUTION_TIME);
} catch (InterruptedException e) {
logger.error("Error while executing sample job", e);
} finally {
count.incrementAndGet();
logger.info("Sample job has finished...");
}
}
public int getNumberOfInvocations() {
return count.get();
}
}
@@ -0,0 +1,31 @@
package org.baeldung.springquartz.config;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
/**
* Adds auto-wiring support to quartz jobs.
* @see "https://gist.github.com/jelies/5085593"
*/
public final class AutoWiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
private transient AutowireCapableBeanFactory beanFactory;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
beanFactory = applicationContext.getAutowireCapableBeanFactory();
}
@Override
protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
final Object job = super.createJobInstance(bundle);
beanFactory.autowireBean(job);
return job;
}
}
@@ -0,0 +1,10 @@
using.spring.schedulerFactory=true
spring.quartz.job-store-type=jdbc
# Always create the Quartz database on startup
spring.quartz.jdbc.initialize-schema=always
spring.datasource.jdbc-url=jdbc:h2:mem:spring-quartz;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<logger name="org.springframework" level="WARN" />
<logger name="org.springframework.transaction" level="WARN" />
<!-- in order to debug some marshalling issues, this needs to be TRACE -->
<logger name="org.springframework.web.servlet.mvc" level="WARN" />
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
@@ -0,0 +1,22 @@
# thread-pool
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount=2
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true
# job-store
# Enable this property for RAMJobStore
#org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore
# Enable these properties for a JDBCJobStore using JobStoreTX
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.dataSource=quartzDataSource
# Enable this property for JobStoreCMT
#org.quartz.jobStore.nonManagedTXDataSource=quartzDataSource
# H2 database
# use an in-memory database & initialise Quartz using their standard SQL script
org.quartz.dataSource.quartzDataSource.URL=jdbc:h2:mem:spring-quartz;INIT=RUNSCRIPT FROM 'classpath:/org/quartz/impl/jdbcjobstore/tables_h2.sql'
org.quartz.dataSource.quartzDataSource.driver=org.h2.Driver
org.quartz.dataSource.quartzDataSource.user=sa
org.quartz.dataSource.quartzDataSource.password=
@@ -0,0 +1,30 @@
package org.baeldung;
import org.baeldung.springquartz.SpringQuartzApp;
import org.baeldung.springquartz.basics.service.SampleJobService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringQuartzApp.class)
public class SpringContextIntegrationTest {
@Autowired
private SampleJobService sampleJobService;
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
@Test
public void whenSchedulerStarts_thenJobsRun() throws InterruptedException {
assertThat(sampleJobService.getNumberOfInvocations()).isEqualTo(0);
Thread.sleep(SampleJobService.EXECUTION_TIME);
assertThat(sampleJobService.getNumberOfInvocations()).isEqualTo(1);
}
}
@@ -0,0 +1,16 @@
package org.baeldung;
import org.baeldung.springquartz.SpringQuartzApp;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringQuartzApp.class)
public class SpringContextTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}