Skip to content

Commit 26a02ca

Browse files
committed
集成Quartz
1 parent 36e33ed commit 26a02ca

File tree

20 files changed

+1394
-1
lines changed

20 files changed

+1394
-1
lines changed

api-boot-project/api-boot-autoconfigure/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,12 @@
110110
<optional>true</optional>
111111
</dependency>
112112

113+
<!--ApiBoot Quartz Plugin-->
114+
<dependency>
115+
<groupId>org.minbox.framework</groupId>
116+
<artifactId>api-boot-plugin-quartz</artifactId>
117+
<optional>true</optional>
118+
</dependency>
113119

114120
</dependencies>
115121
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
package org.minbox.framework.api.boot.autoconfigure.quartz;
2+
3+
import org.minbox.framework.api.boot.quartz.ApiBootQuartzService;
4+
import org.minbox.framework.api.boot.quartz.support.ApiBootQuartzServiceDefaultSupport;
5+
import org.quartz.Scheduler;
6+
import org.quartz.spi.TriggerFiredBundle;
7+
import org.springframework.beans.BeansException;
8+
import org.springframework.beans.factory.ObjectProvider;
9+
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
10+
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
11+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
12+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
13+
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
14+
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
15+
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
16+
import org.springframework.boot.autoconfigure.transaction.PlatformTransactionManagerCustomizer;
17+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
18+
import org.springframework.context.ApplicationContext;
19+
import org.springframework.context.ApplicationContextAware;
20+
import org.springframework.context.annotation.Bean;
21+
import org.springframework.context.annotation.Configuration;
22+
import org.springframework.core.annotation.Order;
23+
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
24+
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
25+
import org.springframework.transaction.PlatformTransactionManager;
26+
27+
import javax.sql.DataSource;
28+
import java.lang.reflect.Field;
29+
import java.util.Arrays;
30+
import java.util.List;
31+
import java.util.Map;
32+
import java.util.Properties;
33+
34+
/**
35+
* ApiBoot Quartz 自动化配置类
36+
*
37+
* @author:恒宇少年 - 于起宇
38+
* <p>
39+
* DateTime:2019-03-27 15:24
40+
* Blog:http://blog.yuqiyu.com
41+
* WebSite:http://www.jianshu.com/u/092df3f77bca
42+
* Gitee:https://gitee.com/hengboy
43+
* GitHub:https://github.com/hengboy
44+
*/
45+
@Configuration
46+
@EnableConfigurationProperties(ApiBootQuartzProperties.class)
47+
@ConditionalOnClass({Scheduler.class, SchedulerFactoryBean.class, PlatformTransactionManagerCustomizer.class, ApiBootQuartzService.class})
48+
@AutoConfigureAfter({DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
49+
public class ApiBootQuartzAutoConfiguration {
50+
51+
private ApiBootQuartzProperties properties;
52+
private ObjectProvider<List<SchedulerFactoryBeanCustomizer>> customizers;
53+
54+
public ApiBootQuartzAutoConfiguration(ApiBootQuartzProperties properties, ObjectProvider<List<SchedulerFactoryBeanCustomizer>> customizers) {
55+
this.properties = properties;
56+
this.customizers = customizers;
57+
}
58+
59+
/**
60+
* 实例化ApiBoot Quartz Service
61+
*
62+
* @param scheduler Quartz Scheduler Instance
63+
* @return ApiBootQuartzService
64+
*/
65+
@Bean
66+
@ConditionalOnMissingBean(ApiBootQuartzService.class)
67+
public ApiBootQuartzService apiBootQuartzService(Scheduler scheduler) {
68+
return new ApiBootQuartzServiceDefaultSupport(scheduler);
69+
}
70+
71+
/**
72+
* APIBoot Quartz Bean Factory
73+
*
74+
* @return ApiBootQuartzSpringBeanJobFactory
75+
*/
76+
@Bean
77+
@ConditionalOnMissingBean
78+
public ApiBootQuartzSpringBeanJobFactory apiBootQuartzSpringBeanJobFactory() {
79+
return new ApiBootQuartzSpringBeanJobFactory();
80+
}
81+
82+
/**
83+
* Quartz Factory Bean
84+
*
85+
* @return SchedulerFactoryBean
86+
*/
87+
@Bean
88+
@ConditionalOnMissingBean
89+
public SchedulerFactoryBean quartzScheduler(ApiBootQuartzSpringBeanJobFactory jobFactory) {
90+
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
91+
92+
schedulerFactoryBean.setJobFactory(jobFactory);
93+
schedulerFactoryBean.setAutoStartup(this.properties.isAutoStartup());
94+
schedulerFactoryBean.setStartupDelay((int) this.properties.getStartupDelay().getSeconds());
95+
schedulerFactoryBean.setWaitForJobsToCompleteOnShutdown(this.properties.isWaitForJobsToCompleteOnShutdown());
96+
schedulerFactoryBean.setOverwriteExistingJobs(this.properties.isOverwriteExistingJobs());
97+
if (!this.properties.getProperties().isEmpty()) {
98+
schedulerFactoryBean.setQuartzProperties(this.asProperties(this.properties.getProperties()));
99+
}
100+
101+
// 自定义配置
102+
this.customize(schedulerFactoryBean);
103+
return schedulerFactoryBean;
104+
}
105+
106+
107+
private Properties asProperties(Map<String, String> source) {
108+
Properties properties = new Properties();
109+
properties.putAll(source);
110+
return properties;
111+
}
112+
113+
private void customize(SchedulerFactoryBean schedulerFactoryBean) {
114+
this.customizers.getIfAvailable().stream().forEach((customizer) -> customizer.customize(schedulerFactoryBean));
115+
}
116+
117+
/**
118+
* ApiBoot Quartz Bean Factory
119+
*
120+
* @author 恒宇少年
121+
* @date 2019-3-30
122+
*/
123+
protected static class ApiBootQuartzSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
124+
/**
125+
* bean factory
126+
*/
127+
private AutowireCapableBeanFactory beanFactory;
128+
129+
/**
130+
* Set Application Context
131+
*
132+
* @param applicationContext Spring Context
133+
* @throws BeansException Bean Exception
134+
*/
135+
@Override
136+
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
137+
this.beanFactory = applicationContext.getAutowireCapableBeanFactory();
138+
}
139+
140+
@Override
141+
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
142+
Object jobInstance = super.createJobInstance(bundle);
143+
beanFactory.autowireBean(jobInstance);
144+
return jobInstance;
145+
}
146+
}
147+
148+
/**
149+
* Job Store Type Config
150+
*/
151+
@Configuration
152+
@ConditionalOnSingleCandidate(DataSource.class)
153+
protected static class JdbcStoreTypeConfiguration {
154+
protected JdbcStoreTypeConfiguration() {
155+
}
156+
157+
/**
158+
* properties needed to initialize Jdbc mode
159+
*
160+
* @return
161+
*/
162+
@Bean
163+
@Order(0)
164+
public SchedulerFactoryBeanCustomizer jobPropertiesCustomizer(ApiBootQuartzProperties properties) {
165+
return schedulerFactoryBean -> {
166+
// jdbc away
167+
if (properties.getJobStoreType() == JobStoreType.JDBC) {
168+
169+
ApiBootQuartzProperties.Prop prop = properties.getProp();
170+
// get prop class declared fields
171+
Field[] fields = prop.getClass().getDeclaredFields();
172+
Arrays.stream(fields).forEach(field -> {
173+
try {
174+
field.setAccessible(true);
175+
String value = String.valueOf(field.get(prop));
176+
PropKey propKey = field.getDeclaredAnnotation(PropKey.class);
177+
178+
// put prop to quartz properties
179+
properties.getProperties().put(propKey.value(), value);
180+
} catch (IllegalAccessException e) {
181+
e.printStackTrace();
182+
}
183+
184+
});
185+
}
186+
};
187+
}
188+
189+
@Bean
190+
@Order(1)
191+
public SchedulerFactoryBeanCustomizer jobDataSourceCustomizer(ApiBootQuartzProperties properties, DataSource dataSource, @QuartzDataSource ObjectProvider<DataSource> quartzDataSource, ObjectProvider<PlatformTransactionManager> transactionManager) {
192+
return (schedulerFactoryBean) -> {
193+
// 数据源配置
194+
if (properties.getJobStoreType() == JobStoreType.JDBC) {
195+
DataSource dataSourceToUse = this.getDataSource(dataSource, quartzDataSource);
196+
schedulerFactoryBean.setDataSource(dataSourceToUse);
197+
PlatformTransactionManager txManager = transactionManager.getIfUnique();
198+
if (txManager != null) {
199+
schedulerFactoryBean.setTransactionManager(txManager);
200+
}
201+
}
202+
203+
};
204+
}
205+
206+
private DataSource getDataSource(DataSource dataSource, ObjectProvider<DataSource> quartzDataSource) {
207+
DataSource dataSourceIfAvailable = quartzDataSource.getIfAvailable();
208+
return dataSourceIfAvailable != null ? dataSourceIfAvailable : dataSource;
209+
}
210+
}
211+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
package org.minbox.framework.api.boot.autoconfigure.quartz;
2+
3+
import lombok.Data;
4+
import lombok.Getter;
5+
import lombok.Setter;
6+
import org.springframework.boot.context.properties.ConfigurationProperties;
7+
import org.springframework.context.annotation.Configuration;
8+
9+
import java.time.Duration;
10+
import java.util.HashMap;
11+
import java.util.Map;
12+
13+
import static org.minbox.framework.api.boot.autoconfigure.quartz.ApiBootQuartzProperties.API_BOOT_QUARTZ_PREFIX;
14+
15+
/**
16+
* ApiBoot Quartz 配置类
17+
*
18+
* @author:恒宇少年 - 于起宇
19+
* <p>
20+
* DateTime:2019-03-27 15:32
21+
* Blog:http://blog.yuqiyu.com
22+
* WebSite:http://www.jianshu.com/u/092df3f77bca
23+
* Gitee:https://gitee.com/hengboy
24+
* GitHub:https://github.com/hengboy
25+
*/
26+
@Data
27+
@Configuration
28+
@ConfigurationProperties(prefix = API_BOOT_QUARTZ_PREFIX)
29+
public class ApiBootQuartzProperties {
30+
/**
31+
* quartz 配置前缀
32+
*/
33+
public static final String API_BOOT_QUARTZ_PREFIX = "api.boot.quartz";
34+
/**
35+
* Quartz job store type.
36+
*/
37+
private JobStoreType jobStoreType = JobStoreType.MEMORY;
38+
39+
/**
40+
* Name of the scheduler.
41+
*/
42+
private String schedulerName;
43+
44+
/**
45+
* Whether to automatically start the scheduler after initialization.
46+
*/
47+
private boolean autoStartup = true;
48+
49+
/**
50+
* Delay after which the scheduler is started once initialization completes. Setting
51+
* this property makes sense if no jobs should be run before the entire application
52+
* has started up.
53+
*/
54+
private Duration startupDelay = Duration.ofSeconds(0);
55+
56+
/**
57+
* Whether to wait for running jobs to complete on shutdown.
58+
*/
59+
private boolean waitForJobsToCompleteOnShutdown = false;
60+
61+
/**
62+
* Whether configured jobs should overwrite existing job definitions.
63+
*/
64+
private boolean overwriteExistingJobs = false;
65+
66+
/**
67+
* Additional Quartz Scheduler properties.
68+
*/
69+
private final Map<String, String> properties = new HashMap<>();
70+
/**
71+
* prop config
72+
* all param have default value
73+
*/
74+
private final ApiBootQuartzProperties.Prop prop = new ApiBootQuartzProperties.Prop();
75+
76+
private final ApiBootQuartzProperties.Jdbc jdbc = new ApiBootQuartzProperties.Jdbc();
77+
78+
/**
79+
* org.minbox.framework.api.boot.autoconfigure.quartz.ApiBootQuartzProperties#properties
80+
* <p>
81+
* quartz properties config
82+
*/
83+
@Getter
84+
@Setter
85+
public static class Prop {
86+
@PropKey("org.quartz.scheduler.instanceName")
87+
private String schedulerInstanceName = "jobScheduler";
88+
89+
@PropKey("org.quartz.scheduler.instanceId")
90+
private String schedulerInstanceId = "AUTO";
91+
92+
@PropKey("org.quartz.jobStore.class")
93+
private String jobStoreClass = "org.quartz.impl.jdbcjobstore.JobStoreTX";
94+
95+
@PropKey("org.quartz.jobStore.driverDelegateClass")
96+
private String jobStoreDriverDelegateClass = "org.quartz.impl.jdbcjobstore.StdJDBCDelegate";
97+
98+
@PropKey("org.quartz.jobStore.tablePrefix")
99+
private String jobStoreTablePrefix = "QRTZ_";
100+
101+
@PropKey("org.quartz.jobStore.isClustered")
102+
private boolean jobStoreClustered = true;
103+
104+
@PropKey("org.quartz.jobStore.clusterCheckinInterval")
105+
private long jobStoreClusterCheckinInterval = 20000;
106+
107+
@PropKey("org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread")
108+
private boolean threadPoolThreadsInheritContextClassLoaderOfInitializingThread = true;
109+
}
110+
111+
public static class Jdbc {
112+
113+
private static final String DEFAULT_SCHEMA_LOCATION = "classpath:org/quartz/impl/"
114+
+ "jdbcjobstore/tables_@@platform@@.sql";
115+
116+
/**
117+
* Path to the SQL file to use to initialize the database schema.
118+
*/
119+
private String schema = DEFAULT_SCHEMA_LOCATION;
120+
121+
/**
122+
* Prefix for single-line comments in SQL initialization scripts.
123+
*/
124+
private String commentPrefix = "--";
125+
126+
public String getSchema() {
127+
return this.schema;
128+
}
129+
130+
public void setSchema(String schema) {
131+
this.schema = schema;
132+
}
133+
134+
public String getCommentPrefix() {
135+
return this.commentPrefix;
136+
}
137+
138+
public void setCommentPrefix(String commentPrefix) {
139+
this.commentPrefix = commentPrefix;
140+
}
141+
142+
}
143+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package org.minbox.framework.api.boot.autoconfigure.quartz;
2+
3+
/**
4+
* Define the supported Quartz {@code JobStore}.
5+
*
6+
* @author:恒宇少年 - 于起宇
7+
* <p>
8+
* DateTime:2019-03-30 13:17
9+
* Blog:http://blog.yuqiyu.com
10+
* WebSite:http://www.jianshu.com/u/092df3f77bca
11+
* Gitee:https://gitee.com/hengboy
12+
* GitHub:https://github.com/hengboy
13+
*/
14+
public enum JobStoreType {
15+
16+
/**
17+
* Store jobs in memory.
18+
*/
19+
MEMORY,
20+
21+
/**
22+
* Store jobs in the database.
23+
*/
24+
JDBC
25+
26+
}

0 commit comments

Comments
 (0)