6aspec 2.0.0-dev.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.6aspec/rules/biz/api_rule.md +578 -0
- package/.6aspec/rules/biz/background_job_rule.md +719 -0
- package/.6aspec/rules/biz/c_user_system_rule.md +240 -0
- package/.6aspec/rules/biz/code.md +39 -0
- package/.6aspec/rules/biz/event_subscriber_rule.md +529 -0
- package/.6aspec/rules/biz/project-structure.md +90 -0
- package/.6aspec/rules/biz/scheduled_job_rule.md +850 -0
- package/.6aspec/rules/brown/brown_archive_sop.md +132 -0
- package/.6aspec/rules/brown/brown_constitution.md +20 -0
- package/.6aspec/rules/brown/brown_continue_sop.md +97 -0
- package/.6aspec/rules/brown/brown_design_sop.md +155 -0
- package/.6aspec/rules/brown/brown_ff_sop.md +194 -0
- package/.6aspec/rules/brown/brown_impact_sop.md +293 -0
- package/.6aspec/rules/brown/brown_implement_sop.md +133 -0
- package/.6aspec/rules/brown/brown_list_sop.md +69 -0
- package/.6aspec/rules/brown/brown_new_sop.md +257 -0
- package/.6aspec/rules/brown/brown_proposal_sop.md +160 -0
- package/.6aspec/rules/brown/brown_quick_sop.md +134 -0
- package/.6aspec/rules/brown/brown_review_sop.md +270 -0
- package/.6aspec/rules/brown/brown_rollback_sop.md +188 -0
- package/.6aspec/rules/brown/brown_specs_sop.md +228 -0
- package/.6aspec/rules/brown/brown_status_sop.md +135 -0
- package/.6aspec/rules/brown/brown_tasks_sop.md +202 -0
- package/.6aspec/rules/brown/brown_understand_sop.md +208 -0
- package/.6aspec/rules/brown/brown_verify_sop.md +360 -0
- package/.6aspec/rules/green/6A_archive_sop.md +301 -0
- package/.6aspec/rules/green/6A_clarify_sop.md +238 -0
- package/.6aspec/rules/green/6A_code_implementation_sop.md +110 -0
- package/.6aspec/rules/green/6A_constitution.md +52 -0
- package/.6aspec/rules/green/6A_continue_sop.md +186 -0
- package/.6aspec/rules/green/6A_design_sop.md +228 -0
- package/.6aspec/rules/green/6A_import_model_table_sop.md +120 -0
- package/.6aspec/rules/green/6A_init_event_list_sop.md +62 -0
- package/.6aspec/rules/green/6A_init_map_sop.md +79 -0
- package/.6aspec/rules/green/6A_model_sop.md +210 -0
- package/.6aspec/rules/green/6A_new_sop.md +319 -0
- package/.6aspec/rules/green/6A_rollback_sop.md +198 -0
- package/.6aspec/rules/green/6A_status_sop.md +275 -0
- package/.6aspec/rules/green/6A_tasks_sop.md +181 -0
- package/.6aspec/rules/green/6A_visual_logic_sop.md +121 -0
- package/.6aspec/rules/green/green_status_schema.md +293 -0
- package/.6aspec/script/create_entities_from_markdown.py +688 -0
- package/.claude/commands/6aspec/brown/archive.md +11 -0
- package/.claude/commands/6aspec/brown/continue.md +11 -0
- package/.claude/commands/6aspec/brown/design.md +11 -0
- package/.claude/commands/6aspec/brown/ff.md +11 -0
- package/.claude/commands/6aspec/brown/impact.md +11 -0
- package/.claude/commands/6aspec/brown/implement.md +11 -0
- package/.claude/commands/6aspec/brown/list.md +11 -0
- package/.claude/commands/6aspec/brown/new.md +11 -0
- package/.claude/commands/6aspec/brown/proposal.md +11 -0
- package/.claude/commands/6aspec/brown/quick.md +11 -0
- package/.claude/commands/6aspec/brown/review.md +11 -0
- package/.claude/commands/6aspec/brown/rollback.md +11 -0
- package/.claude/commands/6aspec/brown/specs.md +11 -0
- package/.claude/commands/6aspec/brown/status.md +11 -0
- package/.claude/commands/6aspec/brown/tasks.md +11 -0
- package/.claude/commands/6aspec/brown/understand.md +11 -0
- package/.claude/commands/6aspec/brown/verify.md +11 -0
- package/.claude/commands/6aspec/green/archive.md +8 -0
- package/.claude/commands/6aspec/green/clarify.md +13 -0
- package/.claude/commands/6aspec/green/continue.md +8 -0
- package/.claude/commands/6aspec/green/design.md +8 -0
- package/.claude/commands/6aspec/green/execute-task.md +20 -0
- package/.claude/commands/6aspec/green/import-model-table.md +8 -0
- package/.claude/commands/6aspec/green/init.md +14 -0
- package/.claude/commands/6aspec/green/model.md +12 -0
- package/.claude/commands/6aspec/green/new.md +13 -0
- package/.claude/commands/6aspec/green/rollback.md +8 -0
- package/.claude/commands/6aspec/green/status.md +8 -0
- package/.claude/commands/6aspec/green/tasks.md +8 -0
- package/.claude/commands/6aspec/green/visual-logic.md +9 -0
- package/.claude/settings.local.json +8 -0
- package/.cursor/commands/6aspec/brown/archive.md +9 -0
- package/.cursor/commands/6aspec/brown/continue.md +9 -0
- package/.cursor/commands/6aspec/brown/design.md +9 -0
- package/.cursor/commands/6aspec/brown/ff.md +9 -0
- package/.cursor/commands/6aspec/brown/impact.md +9 -0
- package/.cursor/commands/6aspec/brown/implement.md +9 -0
- package/.cursor/commands/6aspec/brown/list.md +9 -0
- package/.cursor/commands/6aspec/brown/new.md +9 -0
- package/.cursor/commands/6aspec/brown/proposal.md +9 -0
- package/.cursor/commands/6aspec/brown/quick.md +9 -0
- package/.cursor/commands/6aspec/brown/review.md +9 -0
- package/.cursor/commands/6aspec/brown/rollback.md +9 -0
- package/.cursor/commands/6aspec/brown/specs.md +9 -0
- package/.cursor/commands/6aspec/brown/status.md +9 -0
- package/.cursor/commands/6aspec/brown/tasks.md +9 -0
- package/.cursor/commands/6aspec/brown/understand.md +9 -0
- package/.cursor/commands/6aspec/brown/verify.md +9 -0
- package/.cursor/commands/6aspec/green/archive.md +9 -0
- package/.cursor/commands/6aspec/green/clarify.md +14 -0
- package/.cursor/commands/6aspec/green/continue.md +9 -0
- package/.cursor/commands/6aspec/green/design.md +9 -0
- package/.cursor/commands/6aspec/green/execute-task.md +21 -0
- package/.cursor/commands/6aspec/green/import-model-table.md +9 -0
- package/.cursor/commands/6aspec/green/init.md +15 -0
- package/.cursor/commands/6aspec/green/model.md +13 -0
- package/.cursor/commands/6aspec/green/new.md +14 -0
- package/.cursor/commands/6aspec/green/rollback.md +9 -0
- package/.cursor/commands/6aspec/green/status.md +9 -0
- package/.cursor/commands/6aspec/green/tasks.md +9 -0
- package/.cursor/commands/6aspec/green/visual-logic.md +10 -0
- package/README.en.md +36 -0
- package/README.md +146 -0
- package/bin/6a-spec-install +54 -0
- package/bin/6aspec +64 -0
- package/lib/cli.js +451 -0
- package/lib/installer.js +333 -0
- package/package.json +62 -0
|
@@ -0,0 +1,850 @@
|
|
|
1
|
+
# 定时任务开发规范
|
|
2
|
+
|
|
3
|
+
## 概述
|
|
4
|
+
|
|
5
|
+
本规范定义了系统中定时任务的开发标准,包括 Java 类编写规范、XML 配置文件规范、命名规范等。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 一、定时任务组成
|
|
10
|
+
|
|
11
|
+
每个定时任务由 **两部分** 组成:
|
|
12
|
+
|
|
13
|
+
### 1.1 Java 类(必需)
|
|
14
|
+
|
|
15
|
+
**包路径规范**:
|
|
16
|
+
```
|
|
17
|
+
**.job.schedule
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**开发规范**:
|
|
21
|
+
- 实现定时任务执行逻辑
|
|
22
|
+
- 包含任务调度的核心业务代码
|
|
23
|
+
- 继承框架提供的 Job 基类或实现 Job 接口
|
|
24
|
+
|
|
25
|
+
### 1.2 XML 配置文件(必需)
|
|
26
|
+
|
|
27
|
+
**文件路径规范**:
|
|
28
|
+
```
|
|
29
|
+
{项目根目录}/data/task/{任务UUID}.xml
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**说明**:
|
|
33
|
+
- 每个定时任务对应一个独立的 XML 配置文件
|
|
34
|
+
- 文件名为任务的唯一标识 UUID
|
|
35
|
+
- 包含任务的调度配置(Cron 表达式、执行参数等)
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 二、Java 类开发规范
|
|
40
|
+
|
|
41
|
+
### 2.1 包结构
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
com.mysoft.rental.{module}.job.schedule
|
|
45
|
+
├── {TaskName}Job.java # 定时任务类
|
|
46
|
+
├── {业务分类}/ # 按业务领域分类(可选)
|
|
47
|
+
│ └── {TaskName}Job.java
|
|
48
|
+
└── ...
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 2.2 类命名规范
|
|
52
|
+
|
|
53
|
+
**格式**:`{任务描述}Job`
|
|
54
|
+
|
|
55
|
+
| 场景 | 命名格式 | 示例 |
|
|
56
|
+
|------|---------|------|
|
|
57
|
+
| 数据同步任务 | `{DataName}SyncJob` | `RoomStatusSyncExceptionJob` |
|
|
58
|
+
| 数据清理任务 | `{DataName}CleanJob` | `ExpiredDataCleanJob` |
|
|
59
|
+
| 数据统计任务 | `{DataName}StatisticsJob` | `DailyReportStatisticsJob` |
|
|
60
|
+
| 通知提醒任务 | `{EventName}NotificationJob` | `ContractExpiryNotificationJob` |
|
|
61
|
+
| 数据校验任务 | `{DataName}ValidateJob` | `DataConsistencyValidateJob` |
|
|
62
|
+
|
|
63
|
+
**命名规则**:
|
|
64
|
+
- 使用清晰、语义化的名称
|
|
65
|
+
- 体现任务的业务目的
|
|
66
|
+
- 统一以 `Job` 结尾
|
|
67
|
+
|
|
68
|
+
### 2.3 类结构模板
|
|
69
|
+
|
|
70
|
+
```java
|
|
71
|
+
package com.mysoft.rental.{module}.job.schedule;
|
|
72
|
+
|
|
73
|
+
import lombok.extern.slf4j.Slf4j;
|
|
74
|
+
import org.springframework.beans.factory.annotation.Autowired;
|
|
75
|
+
import org.springframework.stereotype.Component;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* {任务描述}定时任务
|
|
79
|
+
*
|
|
80
|
+
* @author {作者}
|
|
81
|
+
* @description {详细描述任务的作用}
|
|
82
|
+
* @date {创建日期}
|
|
83
|
+
*/
|
|
84
|
+
@Slf4j
|
|
85
|
+
@Component
|
|
86
|
+
public class XxxJob {
|
|
87
|
+
|
|
88
|
+
@Autowired
|
|
89
|
+
private XxxService xxxService;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 执行定时任务
|
|
93
|
+
*
|
|
94
|
+
* @description {任务执行逻辑描述}
|
|
95
|
+
*/
|
|
96
|
+
public void execute() {
|
|
97
|
+
log.info("开始执行【{}】定时任务", "任务名称");
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
// 1. 任务前置检查
|
|
101
|
+
if (!preCheck()) {
|
|
102
|
+
log.warn("【{}】定时任务前置检查未通过,跳过执行", "任务名称");
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// 2. 执行核心业务逻辑
|
|
107
|
+
executeCore();
|
|
108
|
+
|
|
109
|
+
// 3. 任务后置处理(可选)
|
|
110
|
+
postProcess();
|
|
111
|
+
|
|
112
|
+
log.info("【{}】定时任务执行完成", "任务名称");
|
|
113
|
+
|
|
114
|
+
} catch (Exception e) {
|
|
115
|
+
log.error("【{}】定时任务执行异常", "任务名称", e);
|
|
116
|
+
// 不抛出异常,避免影响下次调度
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* 前置检查
|
|
122
|
+
*/
|
|
123
|
+
private boolean preCheck() {
|
|
124
|
+
// 检查任务执行条件
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* 核心业务逻辑
|
|
130
|
+
*/
|
|
131
|
+
private void executeCore() {
|
|
132
|
+
// 业务处理逻辑
|
|
133
|
+
xxxService.handleTask();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* 后置处理
|
|
138
|
+
*/
|
|
139
|
+
private void postProcess() {
|
|
140
|
+
// 清理资源、统计数据等
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### 2.4 关键要点
|
|
146
|
+
|
|
147
|
+
#### 2.4.1 类注解
|
|
148
|
+
|
|
149
|
+
**必需注解**:
|
|
150
|
+
- `@Component` 或 `@Service` - 让 Spring 管理
|
|
151
|
+
- `@Slf4j` - 日志记录
|
|
152
|
+
|
|
153
|
+
```java
|
|
154
|
+
@Slf4j
|
|
155
|
+
@Component
|
|
156
|
+
public class RoomStatusSyncExceptionJob {
|
|
157
|
+
// ...
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
#### 2.4.2 执行方法
|
|
162
|
+
|
|
163
|
+
**方法命名**:
|
|
164
|
+
- 常用方法名:`execute()`、`run()`、`process()`
|
|
165
|
+
- 使用无参方法,参数通过配置文件传递
|
|
166
|
+
|
|
167
|
+
**方法特点**:
|
|
168
|
+
- `public` 访问修饰符
|
|
169
|
+
- `void` 返回类型(不返回值)
|
|
170
|
+
- 无参数或少量参数
|
|
171
|
+
|
|
172
|
+
```java
|
|
173
|
+
public void execute() {
|
|
174
|
+
// 任务执行逻辑
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
#### 2.4.3 异常处理
|
|
179
|
+
|
|
180
|
+
**原则**:捕获所有异常,不向外抛出
|
|
181
|
+
|
|
182
|
+
```java
|
|
183
|
+
public void execute() {
|
|
184
|
+
try {
|
|
185
|
+
// 业务逻辑
|
|
186
|
+
} catch (BusinessLogicException e) {
|
|
187
|
+
log.error("业务处理异常:{}", e.getMessage(), e);
|
|
188
|
+
} catch (Exception e) {
|
|
189
|
+
log.error("系统异常", e);
|
|
190
|
+
}
|
|
191
|
+
// 不抛出异常,确保下次调度不受影响
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**原因**:
|
|
196
|
+
- 避免异常导致任务从调度器中移除
|
|
197
|
+
- 确保定时任务持续执行
|
|
198
|
+
- 通过日志记录问题,便于排查
|
|
199
|
+
|
|
200
|
+
#### 2.4.4 日志规范
|
|
201
|
+
|
|
202
|
+
**必需日志**:
|
|
203
|
+
- 任务开始:`log.info("开始执行【XXX】定时任务")`
|
|
204
|
+
- 任务完成:`log.info("【XXX】定时任务执行完成")`
|
|
205
|
+
- 异常情况:`log.error("【XXX】定时任务执行异常", e)`
|
|
206
|
+
|
|
207
|
+
**建议日志**:
|
|
208
|
+
- 关键节点:记录处理进度
|
|
209
|
+
- 数据统计:记录处理数量
|
|
210
|
+
|
|
211
|
+
```java
|
|
212
|
+
public void execute() {
|
|
213
|
+
log.info("开始执行【房态同步异常处理】定时任务");
|
|
214
|
+
|
|
215
|
+
try {
|
|
216
|
+
List<Data> dataList = xxxService.queryData();
|
|
217
|
+
log.info("【房态同步异常处理】查询到 {} 条待处理数据", dataList.size());
|
|
218
|
+
|
|
219
|
+
int successCount = 0;
|
|
220
|
+
int failCount = 0;
|
|
221
|
+
|
|
222
|
+
for (Data data : dataList) {
|
|
223
|
+
try {
|
|
224
|
+
xxxService.process(data);
|
|
225
|
+
successCount++;
|
|
226
|
+
} catch (Exception e) {
|
|
227
|
+
failCount++;
|
|
228
|
+
log.error("处理数据[{}]失败", data.getId(), e);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
log.info("【房态同步异常处理】定时任务执行完成,成功:{},失败:{}", successCount, failCount);
|
|
233
|
+
|
|
234
|
+
} catch (Exception e) {
|
|
235
|
+
log.error("【房态同步异常处理】定时任务执行异常", e);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## 三、XML 配置文件规范
|
|
243
|
+
|
|
244
|
+
### 3.1 文件位置
|
|
245
|
+
|
|
246
|
+
```
|
|
247
|
+
{项目根目录}/data/task/{UUID}.xml
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**示例**:
|
|
251
|
+
```
|
|
252
|
+
rental/data/task/0bc7924a-e6f9-a86e-267e-41adc86427f9.xml
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### 3.2 UUID 生成规则
|
|
256
|
+
|
|
257
|
+
- 使用标准 UUID 格式(8-4-4-4-12)
|
|
258
|
+
- 每个任务唯一
|
|
259
|
+
- 建议使用在线 UUID 生成器或编程生成
|
|
260
|
+
|
|
261
|
+
**生成方式**:
|
|
262
|
+
```java
|
|
263
|
+
UUID uuid = UUID.randomUUID();
|
|
264
|
+
System.out.println(uuid.toString());
|
|
265
|
+
// 输出:0bc7924a-e6f9-a86e-267e-41adc86427f9
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
**重要提示**:
|
|
269
|
+
- `TaskGuid` 的值必须与 XML 文件名保持一致
|
|
270
|
+
- 例如:文件名为 `0bc7924a-e6f9-a86e-267e-41adc86427f9.xml`,则 `<TaskGuid>` 也应为 `0bc7924a-e6f9-a86e-267e-41adc86427f9`
|
|
271
|
+
|
|
272
|
+
### 3.3 XML 文件模板
|
|
273
|
+
|
|
274
|
+
```xml
|
|
275
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
276
|
+
<Task>
|
|
277
|
+
<!-- 任务唯一标识 -->
|
|
278
|
+
<TaskGuid>0bc7924a-e6f9-a86e-267e-41adc86427f9</TaskGuid>
|
|
279
|
+
|
|
280
|
+
<!-- 任务名称 -->
|
|
281
|
+
<TaskName>房态数据同步异常定时任务</TaskName>
|
|
282
|
+
|
|
283
|
+
<!-- 创建人(可选) -->
|
|
284
|
+
<CreateBy></CreateBy>
|
|
285
|
+
|
|
286
|
+
<!-- 任务描述 -->
|
|
287
|
+
<Description>房态数据同步异常定时任务</Description>
|
|
288
|
+
|
|
289
|
+
<!-- 任务级别:PRODUCT(生产环境) -->
|
|
290
|
+
<Level>PRODUCT</Level>
|
|
291
|
+
|
|
292
|
+
<!-- 任务类型:ASYNC(异步) -->
|
|
293
|
+
<Type>ASYNC</Type>
|
|
294
|
+
|
|
295
|
+
<!-- 是否启用:1=启用,0=禁用 -->
|
|
296
|
+
<Enable>1</Enable>
|
|
297
|
+
|
|
298
|
+
<!-- 触发器配置(Cron表达式) -->
|
|
299
|
+
<Triggers>
|
|
300
|
+
<Trigger>0 1 0 * * ?</Trigger> <!-- 每天凌晨1分执行 -->
|
|
301
|
+
</Triggers>
|
|
302
|
+
|
|
303
|
+
<!-- 系统参数配置 -->
|
|
304
|
+
<SystemParameters>
|
|
305
|
+
<SystemParam Name="serviceType" Value="service"/>
|
|
306
|
+
<SystemParam Name="appCode" Value="8501"/>
|
|
307
|
+
<SystemParam Name="requestType" Value="POST"/>
|
|
308
|
+
<SystemParam Name="jobName" Value="RoomStatusSyncExceptionJob"/> <!-- Java类名 -->
|
|
309
|
+
</SystemParameters>
|
|
310
|
+
</Task>
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### 3.4 配置项说明
|
|
314
|
+
|
|
315
|
+
| 配置项 | 是否必需 | 说明 | 示例值 |
|
|
316
|
+
|--------|---------|------|--------|
|
|
317
|
+
| `TaskGuid` | 必需 | 任务唯一标识(UUID) | `0bc7924a-e6f9-a86e-267e-41adc86427f9` |
|
|
318
|
+
| `TaskName` | 必需 | 任务名称(中文) | `房态数据同步异常定时任务` |
|
|
319
|
+
| `CreateBy` | 可选 | 创建人 | 可为空 |
|
|
320
|
+
| `Description` | 必需 | 任务描述 | `房态数据同步异常定时任务` |
|
|
321
|
+
| `Level` | 必需 | 任务级别 | `PRODUCT`(生产环境) |
|
|
322
|
+
| `Type` | 必需 | 任务类型 | `ASYNC`(异步) |
|
|
323
|
+
| `Enable` | 必需 | 是否启用 | `1`(启用)/ `0`(禁用) |
|
|
324
|
+
| `Triggers/Trigger` | 必需 | Cron 表达式 | `0 1 0 * * ?` |
|
|
325
|
+
| `SystemParameters` | 必需 | 系统参数配置 | 见下表 |
|
|
326
|
+
|
|
327
|
+
#### SystemParameters 配置项
|
|
328
|
+
|
|
329
|
+
| 参数名 | 是否必需 | 说明 | 示例值 |
|
|
330
|
+
|--------|---------|------|--------|
|
|
331
|
+
| `serviceType` | 必需 | 服务类型 | `service` |
|
|
332
|
+
| `appCode` | 必需 | 应用编码 | `8501` |
|
|
333
|
+
| `requestType` | 必需 | 请求类型 | `POST` |
|
|
334
|
+
| `jobName` | 必需 | Java 类名(**只写类名,不含包名**) | `RoomStatusSyncExceptionJob` |
|
|
335
|
+
|
|
336
|
+
**重要说明**:
|
|
337
|
+
- `jobName` 只需要填写 **类名**,不需要包含完整的包路径
|
|
338
|
+
- ✅ 正确:`RoomStatusSyncExceptionJob`
|
|
339
|
+
- ❌ 错误:`com.mysoft.rental.caretaker.job.schedule.RoomStatusSyncExceptionJob`
|
|
340
|
+
- `appCode` 通常固定为 `8501`,不同系统可能不同
|
|
341
|
+
|
|
342
|
+
### 3.5 Cron 表达式
|
|
343
|
+
|
|
344
|
+
**格式**:`秒 分 时 日 月 周 [年]`
|
|
345
|
+
|
|
346
|
+
**常用示例**:
|
|
347
|
+
|
|
348
|
+
| 表达式 | 说明 |
|
|
349
|
+
|--------|------|
|
|
350
|
+
| `0 0/10 * * * ?` | 每 10 分钟执行一次 |
|
|
351
|
+
| `0 0 0 * * ?` | 每天凌晨 0 点执行 |
|
|
352
|
+
| `0 0 2 * * ?` | 每天凌晨 2 点执行 |
|
|
353
|
+
| `0 0 0/1 * * ?` | 每小时整点执行 |
|
|
354
|
+
| `0 0 12 * * ?` | 每天中午 12 点执行 |
|
|
355
|
+
| `0 0 0 1 * ?` | 每月 1 号凌晨执行 |
|
|
356
|
+
| `0 0 0 ? * MON` | 每周一凌晨执行 |
|
|
357
|
+
| `0 0 0 1 1 ?` | 每年 1 月 1 日凌晨执行 |
|
|
358
|
+
|
|
359
|
+
**Cron 表达式工具**:
|
|
360
|
+
- 在线生成器:https://cron.qqe2.com/
|
|
361
|
+
- 在线验证器:https://crontab.guru/
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## 四、开发流程
|
|
366
|
+
|
|
367
|
+
### 4.1 创建定时任务的步骤
|
|
368
|
+
|
|
369
|
+
**步骤 1:编写 Java 类**
|
|
370
|
+
```java
|
|
371
|
+
@Slf4j
|
|
372
|
+
@Component
|
|
373
|
+
public class DataSyncJob {
|
|
374
|
+
|
|
375
|
+
@Autowired
|
|
376
|
+
private DataSyncService dataSyncService;
|
|
377
|
+
|
|
378
|
+
public void execute() {
|
|
379
|
+
log.info("开始执行【数据同步】定时任务");
|
|
380
|
+
try {
|
|
381
|
+
dataSyncService.sync();
|
|
382
|
+
log.info("【数据同步】定时任务执行完成");
|
|
383
|
+
} catch (Exception e) {
|
|
384
|
+
log.error("【数据同步】定时任务执行异常", e);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
**步骤 2:生成 UUID**
|
|
391
|
+
```java
|
|
392
|
+
String uuid = UUID.randomUUID().toString();
|
|
393
|
+
// 0bc7924a-e6f9-a86e-267e-41adc86427f9
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
**步骤 3:创建 XML 配置文件**
|
|
397
|
+
- 文件路径:`data/task/0bc7924a-e6f9-a86e-267e-41adc86427f9.xml`
|
|
398
|
+
- 填写配置信息(参考模板)
|
|
399
|
+
- 关键配置:
|
|
400
|
+
- `TaskGuid`:与文件名保持一致
|
|
401
|
+
- `TaskName`:任务中文名称
|
|
402
|
+
- `Enable`:设置为 `1`(启用)
|
|
403
|
+
- `Trigger`:Cron 表达式
|
|
404
|
+
- `jobName`:Java 类名(只写类名,不含包名)
|
|
405
|
+
|
|
406
|
+
**步骤 4:配置 Cron 表达式**
|
|
407
|
+
- 根据业务需求设置执行频率
|
|
408
|
+
- 使用在线工具生成和验证
|
|
409
|
+
|
|
410
|
+
**步骤 5:测试验证**
|
|
411
|
+
- 本地测试任务执行逻辑
|
|
412
|
+
- 验证 Cron 表达式是否符合预期
|
|
413
|
+
- 检查日志输出是否完整
|
|
414
|
+
|
|
415
|
+
**步骤 6:部署上线**
|
|
416
|
+
- 提交代码和 XML 配置文件
|
|
417
|
+
- 服务重启后自动加载任务
|
|
418
|
+
- 监控任务执行情况
|
|
419
|
+
|
|
420
|
+
### 4.2 文件对应关系
|
|
421
|
+
|
|
422
|
+
```
|
|
423
|
+
Java 类
|
|
424
|
+
├── 类名:RoomStatusSyncExceptionJob
|
|
425
|
+
├── 包路径:com.mysoft.rental.caretaker.job.schedule
|
|
426
|
+
└── 文件:RoomStatusSyncExceptionJob.java
|
|
427
|
+
|
|
428
|
+
↓ 对应
|
|
429
|
+
|
|
430
|
+
XML 配置
|
|
431
|
+
├── 文件名:0bc7924a-e6f9-a86e-267e-41adc86427f9.xml
|
|
432
|
+
├── 路径:data/task/0bc7924a-e6f9-a86e-267e-41adc86427f9.xml
|
|
433
|
+
├── <TaskGuid>:0bc7924a-e6f9-a86e-267e-41adc86427f9
|
|
434
|
+
├── <TaskName>:房态数据同步异常定时任务
|
|
435
|
+
└── <SystemParam Name="jobName">:RoomStatusSyncExceptionJob(只写类名)
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
**关键对应关系**:
|
|
439
|
+
1. XML **文件名** = `<TaskGuid>` 的值
|
|
440
|
+
2. `<SystemParam Name="jobName">` = Java **类名**(不含包名)
|
|
441
|
+
3. 一个定时任务 = 1 个 Java 类 + 1 个 XML 配置文件
|
|
442
|
+
|
|
443
|
+
### 4.3 完整示例
|
|
444
|
+
|
|
445
|
+
假设要创建一个"每天凌晨清理过期数据"的定时任务:
|
|
446
|
+
|
|
447
|
+
**第一步:编写 Java 类**
|
|
448
|
+
|
|
449
|
+
文件:`com.mysoft.rental.caretaker.job.schedule.ExpiredDataCleanJob.java`
|
|
450
|
+
|
|
451
|
+
```java
|
|
452
|
+
package com.mysoft.rental.caretaker.job.schedule;
|
|
453
|
+
|
|
454
|
+
import lombok.extern.slf4j.Slf4j;
|
|
455
|
+
import org.springframework.beans.factory.annotation.Autowired;
|
|
456
|
+
import org.springframework.stereotype.Component;
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* 过期数据清理定时任务
|
|
460
|
+
*
|
|
461
|
+
* @author yanghui
|
|
462
|
+
* @description 每天凌晨清理超过30天的过期数据
|
|
463
|
+
* @date 2026-01-11
|
|
464
|
+
*/
|
|
465
|
+
@Slf4j
|
|
466
|
+
@Component
|
|
467
|
+
public class ExpiredDataCleanJob {
|
|
468
|
+
|
|
469
|
+
@Autowired
|
|
470
|
+
private DataCleanService dataCleanService;
|
|
471
|
+
|
|
472
|
+
public void execute() {
|
|
473
|
+
log.info("开始执行【过期数据清理】定时任务");
|
|
474
|
+
|
|
475
|
+
try {
|
|
476
|
+
int count = dataCleanService.cleanExpiredData(30);
|
|
477
|
+
log.info("【过期数据清理】定时任务执行完成,清理了 {} 条数据", count);
|
|
478
|
+
} catch (Exception e) {
|
|
479
|
+
log.error("【过期数据清理】定时任务执行异常", e);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
**第二步:生成 UUID**
|
|
486
|
+
|
|
487
|
+
```java
|
|
488
|
+
UUID.randomUUID().toString()
|
|
489
|
+
// 假设生成:1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
**第三步:创建 XML 配置**
|
|
493
|
+
|
|
494
|
+
文件:`data/task/1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d.xml`
|
|
495
|
+
|
|
496
|
+
```xml
|
|
497
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
498
|
+
<Task>
|
|
499
|
+
<TaskGuid>1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d</TaskGuid>
|
|
500
|
+
<TaskName>过期数据清理定时任务</TaskName>
|
|
501
|
+
<CreateBy>yanghui</CreateBy>
|
|
502
|
+
<Description>每天凌晨清理超过30天的过期数据</Description>
|
|
503
|
+
<Level>PRODUCT</Level>
|
|
504
|
+
<Type>ASYNC</Type>
|
|
505
|
+
<Enable>1</Enable>
|
|
506
|
+
<Triggers>
|
|
507
|
+
<Trigger>0 0 2 * * ?</Trigger> <!-- 每天凌晨2点执行 -->
|
|
508
|
+
</Triggers>
|
|
509
|
+
<SystemParameters>
|
|
510
|
+
<SystemParam Name="serviceType" Value="service"/>
|
|
511
|
+
<SystemParam Name="appCode" Value="8501"/>
|
|
512
|
+
<SystemParam Name="requestType" Value="POST"/>
|
|
513
|
+
<SystemParam Name="jobName" Value="ExpiredDataCleanJob"/>
|
|
514
|
+
</SystemParameters>
|
|
515
|
+
</Task>
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
**完成!**
|
|
519
|
+
- Java 类名:`ExpiredDataCleanJob`
|
|
520
|
+
- XML 文件名:`1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d.xml`
|
|
521
|
+
- TaskGuid:`1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d`
|
|
522
|
+
- jobName:`ExpiredDataCleanJob`(只写类名)
|
|
523
|
+
- 执行时间:每天凌晨 2 点
|
|
524
|
+
|
|
525
|
+
---
|
|
526
|
+
|
|
527
|
+
## 五、最佳实践
|
|
528
|
+
|
|
529
|
+
### 5.1 任务执行时间选择
|
|
530
|
+
|
|
531
|
+
**原则**:避开业务高峰期
|
|
532
|
+
|
|
533
|
+
| 任务类型 | 推荐执行时间 | Cron 示例 |
|
|
534
|
+
|---------|-------------|----------|
|
|
535
|
+
| 数据统计任务 | 凌晨 2-5 点 | `0 0 2 * * ?` |
|
|
536
|
+
| 数据同步任务 | 每小时或每 10 分钟 | `0 0/10 * * * ?` |
|
|
537
|
+
| 数据清理任务 | 凌晨 3 点 | `0 0 3 * * ?` |
|
|
538
|
+
| 报表生成任务 | 凌晨 1 点 | `0 0 1 * * ?` |
|
|
539
|
+
| 实时监控任务 | 每 5 分钟 | `0 0/5 * * * ?` |
|
|
540
|
+
|
|
541
|
+
### 5.2 批量处理
|
|
542
|
+
|
|
543
|
+
**问题**:大量数据处理可能导致任务超时或内存溢出
|
|
544
|
+
|
|
545
|
+
**解决方案**:分批处理
|
|
546
|
+
|
|
547
|
+
```java
|
|
548
|
+
public void execute() {
|
|
549
|
+
log.info("开始执行【数据处理】定时任务");
|
|
550
|
+
|
|
551
|
+
try {
|
|
552
|
+
int batchSize = 100; // 每批处理数量
|
|
553
|
+
int offset = 0;
|
|
554
|
+
int totalCount = 0;
|
|
555
|
+
|
|
556
|
+
while (true) {
|
|
557
|
+
// 分页查询数据
|
|
558
|
+
List<Data> dataList = xxxService.queryDataByPage(offset, batchSize);
|
|
559
|
+
if (CollectionUtils.isEmpty(dataList)) {
|
|
560
|
+
break; // 没有数据了,退出循环
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// 批量处理
|
|
564
|
+
for (Data data : dataList) {
|
|
565
|
+
try {
|
|
566
|
+
xxxService.process(data);
|
|
567
|
+
totalCount++;
|
|
568
|
+
} catch (Exception e) {
|
|
569
|
+
log.error("处理数据[{}]失败", data.getId(), e);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
offset += batchSize;
|
|
574
|
+
|
|
575
|
+
// 避免长时间占用,适当休眠
|
|
576
|
+
Thread.sleep(100);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
log.info("【数据处理】定时任务执行完成,共处理 {} 条数据", totalCount);
|
|
580
|
+
|
|
581
|
+
} catch (Exception e) {
|
|
582
|
+
log.error("【数据处理】定时任务执行异常", e);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
### 5.3 幂等性保证
|
|
588
|
+
|
|
589
|
+
**问题**:任务重复执行可能导致数据重复处理
|
|
590
|
+
|
|
591
|
+
**解决方案**:
|
|
592
|
+
|
|
593
|
+
**方式一:状态标识**
|
|
594
|
+
```java
|
|
595
|
+
public void execute() {
|
|
596
|
+
// 查询待处理数据(status = 'PENDING')
|
|
597
|
+
List<Data> dataList = xxxService.queryPendingData();
|
|
598
|
+
|
|
599
|
+
for (Data data : dataList) {
|
|
600
|
+
try {
|
|
601
|
+
// 更新状态为处理中
|
|
602
|
+
data.setStatus("PROCESSING");
|
|
603
|
+
xxxService.update(data);
|
|
604
|
+
|
|
605
|
+
// 业务处理
|
|
606
|
+
xxxService.process(data);
|
|
607
|
+
|
|
608
|
+
// 更新状态为已完成
|
|
609
|
+
data.setStatus("COMPLETED");
|
|
610
|
+
xxxService.update(data);
|
|
611
|
+
|
|
612
|
+
} catch (Exception e) {
|
|
613
|
+
// 更新状态为失败
|
|
614
|
+
data.setStatus("FAILED");
|
|
615
|
+
xxxService.update(data);
|
|
616
|
+
log.error("处理失败", e);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
**方式二:分布式锁**
|
|
623
|
+
```java
|
|
624
|
+
@Autowired
|
|
625
|
+
private BaseDistributedLockFactory lockFactory;
|
|
626
|
+
|
|
627
|
+
public void execute() {
|
|
628
|
+
BaseDistributedLock lock = lockFactory.build("data-sync-job");
|
|
629
|
+
|
|
630
|
+
try {
|
|
631
|
+
// 尝试获取锁,避免重复执行
|
|
632
|
+
if (lock.tryLock(1, TimeUnit.SECONDS)) {
|
|
633
|
+
// 执行任务
|
|
634
|
+
executeCore();
|
|
635
|
+
} else {
|
|
636
|
+
log.warn("【数据同步】定时任务正在执行中,跳过本次调度");
|
|
637
|
+
}
|
|
638
|
+
} finally {
|
|
639
|
+
if (lock.isLocked() && lock.isHeldByCurrentThread()) {
|
|
640
|
+
lock.unlock();
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
### 5.4 超时控制
|
|
647
|
+
|
|
648
|
+
**问题**:任务执行时间过长可能影响下次调度
|
|
649
|
+
|
|
650
|
+
**解决方案**:
|
|
651
|
+
|
|
652
|
+
```java
|
|
653
|
+
public void execute() {
|
|
654
|
+
log.info("开始执行【数据处理】定时任务");
|
|
655
|
+
|
|
656
|
+
long startTime = System.currentTimeMillis();
|
|
657
|
+
long timeout = 30 * 60 * 1000; // 30分钟超时
|
|
658
|
+
|
|
659
|
+
try {
|
|
660
|
+
List<Data> dataList = xxxService.queryData();
|
|
661
|
+
|
|
662
|
+
for (Data data : dataList) {
|
|
663
|
+
// 检查是否超时
|
|
664
|
+
if (System.currentTimeMillis() - startTime > timeout) {
|
|
665
|
+
log.warn("【数据处理】定时任务执行超时,剩余数据将在下次执行");
|
|
666
|
+
break;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
try {
|
|
670
|
+
xxxService.process(data);
|
|
671
|
+
} catch (Exception e) {
|
|
672
|
+
log.error("处理数据[{}]失败", data.getId(), e);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
log.info("【数据处理】定时任务执行完成");
|
|
677
|
+
|
|
678
|
+
} catch (Exception e) {
|
|
679
|
+
log.error("【数据处理】定时任务执行异常", e);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
### 5.5 任务监控
|
|
685
|
+
|
|
686
|
+
**建议**:记录任务执行统计信息
|
|
687
|
+
|
|
688
|
+
```java
|
|
689
|
+
public void execute() {
|
|
690
|
+
log.info("开始执行【数据处理】定时任务");
|
|
691
|
+
|
|
692
|
+
long startTime = System.currentTimeMillis();
|
|
693
|
+
int successCount = 0;
|
|
694
|
+
int failCount = 0;
|
|
695
|
+
|
|
696
|
+
try {
|
|
697
|
+
List<Data> dataList = xxxService.queryData();
|
|
698
|
+
log.info("查询到 {} 条待处理数据", dataList.size());
|
|
699
|
+
|
|
700
|
+
for (Data data : dataList) {
|
|
701
|
+
try {
|
|
702
|
+
xxxService.process(data);
|
|
703
|
+
successCount++;
|
|
704
|
+
} catch (Exception e) {
|
|
705
|
+
failCount++;
|
|
706
|
+
log.error("处理数据[{}]失败", data.getId(), e);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
long duration = System.currentTimeMillis() - startTime;
|
|
711
|
+
log.info("【数据处理】定时任务执行完成,耗时:{}ms,成功:{},失败:{}",
|
|
712
|
+
duration, successCount, failCount);
|
|
713
|
+
|
|
714
|
+
// 可选:将统计信息记录到数据库
|
|
715
|
+
xxxService.recordJobStatistics(successCount, failCount, duration);
|
|
716
|
+
|
|
717
|
+
} catch (Exception e) {
|
|
718
|
+
log.error("【数据处理】定时任务执行异常", e);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
---
|
|
724
|
+
|
|
725
|
+
## 六、检查清单
|
|
726
|
+
|
|
727
|
+
### 6.1 Java 类检查
|
|
728
|
+
|
|
729
|
+
在提交代码前,请确认:
|
|
730
|
+
|
|
731
|
+
- [ ] 类名符合命名规范(以 Job 结尾)
|
|
732
|
+
- [ ] 包路径正确(`**.job.schedule`)
|
|
733
|
+
- [ ] 添加了 `@Component` 和 `@Slf4j` 注解
|
|
734
|
+
- [ ] 执行方法为 `public void`
|
|
735
|
+
- [ ] 添加了完整的异常处理(捕获所有异常)
|
|
736
|
+
- [ ] 添加了任务开始和结束的日志
|
|
737
|
+
- [ ] 添加了 JavaDoc 注释(类和方法)
|
|
738
|
+
- [ ] 考虑了批量处理和超时控制
|
|
739
|
+
- [ ] 考虑了幂等性问题
|
|
740
|
+
|
|
741
|
+
### 6.2 XML 配置检查
|
|
742
|
+
|
|
743
|
+
在提交配置前,请确认:
|
|
744
|
+
|
|
745
|
+
- [ ] XML 文件位于 `data/task/` 目录
|
|
746
|
+
- [ ] `TaskGuid` 格式正确且唯一
|
|
747
|
+
- [ ] `TaskName` 和 `Description` 准确描述任务
|
|
748
|
+
- [ ] `Level` 设置为 `PRODUCT`
|
|
749
|
+
- [ ] `Type` 设置为 `ASYNC`
|
|
750
|
+
- [ ] `Enable` 设置正确(1=启用,0=禁用)
|
|
751
|
+
- [ ] `Trigger` 中的 Cron 表达式经过验证
|
|
752
|
+
- [ ] `SystemParameters` 中的 `jobName` 为正确的 Java 类名(不含包名)
|
|
753
|
+
- [ ] `appCode` 设置正确(通常为 `8501`)
|
|
754
|
+
- [ ] XML 格式正确,能够被解析
|
|
755
|
+
|
|
756
|
+
---
|
|
757
|
+
|
|
758
|
+
## 七、常见问题
|
|
759
|
+
|
|
760
|
+
### Q1: 定时任务执行失败会影响下次调度吗?
|
|
761
|
+
- **不会**,只要不抛出异常。
|
|
762
|
+
- 在 `execute()` 方法中捕获所有异常,确保方法正常返回。
|
|
763
|
+
- 失败通过日志记录,便于问题排查。
|
|
764
|
+
|
|
765
|
+
### Q2: 如何临时禁用定时任务?
|
|
766
|
+
- 修改 XML 配置文件中的 `<Enable>` 为 `0`(禁用)。
|
|
767
|
+
- 重启服务后生效。
|
|
768
|
+
- 无需修改 Java 代码。
|
|
769
|
+
|
|
770
|
+
### Q3: 如何调整定时任务的执行频率?
|
|
771
|
+
- 修改 XML 配置文件中 `<Triggers>` 里的 `<Trigger>` 表达式。
|
|
772
|
+
- 重启服务后生效。
|
|
773
|
+
- 建议使用在线工具验证 Cron 表达式。
|
|
774
|
+
|
|
775
|
+
### Q4: 定时任务的执行时间选择有什么建议?
|
|
776
|
+
- **避开业务高峰期**(如工作日 9:00-18:00)
|
|
777
|
+
- **数据统计/清理任务**:建议凌晨 2-5 点执行
|
|
778
|
+
- **实时监控任务**:根据业务需求设置短周期(如每 5 分钟)
|
|
779
|
+
- **批量处理任务**:预留足够的执行时间,避免与下次调度冲突
|
|
780
|
+
|
|
781
|
+
### Q5: 如何处理大量数据?
|
|
782
|
+
- 使用**分批处理**,每批处理固定数量(如 100 条)
|
|
783
|
+
- 添加**超时控制**,避免单次执行时间过长
|
|
784
|
+
- 使用**状态标识**,记录处理进度,支持断点续传
|
|
785
|
+
- 适当添加 `Thread.sleep()`,避免长时间占用资源
|
|
786
|
+
|
|
787
|
+
### Q6: 定时任务需要单元测试吗?
|
|
788
|
+
- **建议编写单元测试**
|
|
789
|
+
- 测试核心业务逻辑,而非调度逻辑
|
|
790
|
+
- 可以直接调用 `execute()` 方法进行测试
|
|
791
|
+
|
|
792
|
+
```java
|
|
793
|
+
@SpringBootTest
|
|
794
|
+
public class DataSyncJobTest {
|
|
795
|
+
|
|
796
|
+
@Autowired
|
|
797
|
+
private DataSyncJob dataSyncJob;
|
|
798
|
+
|
|
799
|
+
@Test
|
|
800
|
+
public void testExecute() {
|
|
801
|
+
// 准备测试数据
|
|
802
|
+
// ...
|
|
803
|
+
|
|
804
|
+
// 执行任务
|
|
805
|
+
dataSyncJob.execute();
|
|
806
|
+
|
|
807
|
+
// 验证结果
|
|
808
|
+
// ...
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
```
|
|
812
|
+
|
|
813
|
+
### Q7: XML 配置文件可以动态修改吗?
|
|
814
|
+
- **可以**,修改后重启服务生效。
|
|
815
|
+
- 有些系统支持热加载,无需重启。
|
|
816
|
+
- 建议通过配置管理平台统一管理。
|
|
817
|
+
|
|
818
|
+
### Q8: Level 和 Type 应该填什么值?
|
|
819
|
+
- **Level**:固定填写 `PRODUCT`(生产环境级别)
|
|
820
|
+
- **Type**:固定填写 `ASYNC`(异步执行)
|
|
821
|
+
- 这两个配置通常不需要修改
|
|
822
|
+
|
|
823
|
+
### Q9: jobName 为什么只写类名不写包名?
|
|
824
|
+
- 这是框架的约定,系统会自动扫描所有 `**.job.schedule` 包下的类
|
|
825
|
+
- 通过类名就能唯一定位到具体的 Job 类
|
|
826
|
+
- 避免配置过长,提高可读性
|
|
827
|
+
|
|
828
|
+
### Q10: 一个 XML 文件可以配置多个触发器吗?
|
|
829
|
+
- 理论上 `<Triggers>` 节点下可以配置多个 `<Trigger>`
|
|
830
|
+
- 建议每个任务只配置一个触发器,保持简洁
|
|
831
|
+
- 如需不同频率,可以创建多个任务
|
|
832
|
+
|
|
833
|
+
---
|
|
834
|
+
|
|
835
|
+
## 八、相关文档
|
|
836
|
+
|
|
837
|
+
- Cron 表达式详解
|
|
838
|
+
- Quartz 调度器使用指南
|
|
839
|
+
- 分布式锁使用规范
|
|
840
|
+
|
|
841
|
+
---
|
|
842
|
+
|
|
843
|
+
**文档版本**:v1.1
|
|
844
|
+
**最后更新**:2026-01-11
|
|
845
|
+
**更新说明**:
|
|
846
|
+
- v1.1: 修正 XML 配置文件模板,使用实际的配置结构(Task/TaskGuid/SystemParameters 等)
|
|
847
|
+
- v1.0: 初始版本
|
|
848
|
+
|
|
849
|
+
**维护人**:开发团队
|
|
850
|
+
|