# 初始化能力使用指南
## 一、初始化机制概述
本项目提供统一的初始化能力,核心方式是继承 `AbstractInitializer` 类实现初始化逻辑。
**设计思想**:
- 所有初始化器统一管理,支持手动触发
- 支持执行顺序控制
- 支持成功/失败结果汇总
- 支持生命周期回调
---
## 二、创建初始化器
### 2.1 基础实现
继承 `AbstractInitializer` 并实现 `execute()` 方法:
```java
@Component
@Slf4j
public class YourDataInitializer extends AbstractInitializer {
@Autowired
private YourService yourService;
@Override
public String getName() {
return "你的数据初始化";
}
@Override
public void execute() {
// 执行初始化逻辑
log.info("开始执行初始化...");
yourService.initData();
log.info("初始化完成");
}
}
2.2 设置执行顺序
使用 @Order 注解控制初始化顺序(数字越小越先执行):
@Order(1)
@Component
public class DepartmentInitializer extends AbstractInitializer {
// 部门初始化(最先执行)
}
@Order(2)
@Component
public class RoleInitializer extends AbstractInitializer {
// 角色初始化(在部门之后执行)
}
@Order(3)
@Component
public class UserInitializer extends AbstractInitializer {
// 用户初始化(在角色之后执行)
}
2.3 生命周期回调
覆盖 onStart() 和 onEnd() 方法:
@Component
@Slf4j
public class YourDataInitializer extends AbstractInitializer {
@Override
public String getName() {
return "你的数据初始化";
}
@Override
public void onStart() {
super.onStart();
log.info("初始化开始前的准备工作");
}
@Override
public void execute() {
log.info("执行初始化逻辑");
}
@Override
public void onEnd(long costTime) {
super.onEnd(costTime);
log.info("初始化结束,耗时: {}ms", costTime);
}
}
三、触发初始化
3.1 手动触发
调用 REST 接口触发所有初始化器:
POST /sys/v1/init/start
Content-Type: application/json
{}
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| 无 | - | - | 当前接口不接受请求体参数 |
接口会执行全部初始化器
请求头:
| Header | 值 | 说明 |
|---|---|---|
tenant-id |
String | 租户ID(多租户场景下必填) |
Authorization |
Bearer Token | 认证令牌 |
请求示例:
curl -X POST http://localhost:8080/sys/v1/init/start \
-H "Content-Type: application/json" \
-H "tenant-id: tenant001" \
-H "Authorization: Bearer your_token_here" \
-d '{}'
响应示例:
{
"code": 200,
"data": {
"success": ["部门初始化", "角色初始化", "用户初始化"],
"fail": []
},
"message": "success"
}
3.2 执行流程
调用 /sys/v1/init/start
↓
遍历所有 AbstractInitializer Bean(按 @Order 排序)
↓
对每个初始化器执行:
onStart()
↓
execute() ← 业务逻辑
↓
onEnd(costTime)
↓
收集成功/失败结果
↓
返回汇总结果
四、完整示例
4.1 示例1:用户初始化器
@Component
@Slf4j
public class UserInitializer extends AbstractInitializer {
@Autowired
private UserService userService;
@Override
public String getName() {
return "用户初始化";
}
@Override
public void execute() {
log.info("开始初始化用户数据...");
// 检查是否已初始化(保证幂等性)
if (userService.count() > 0) {
log.info("用户数据已存在,跳过初始化");
return;
}
// 创建默认用户
UserEntity admin = new UserEntity();
admin.setUserName("admin");
admin.setPassword(PasswordEncoder.encode("admin123"));
admin.setEmail("admin@example.com");
userService.save(admin);
log.info("用户初始化完成");
}
}
4.2 示例2:部门初始化器
@Order(1)
@Component
@Slf4j
public class DepartmentInitializer extends AbstractInitializer {
@Autowired
private DepartmentService departmentService;
@Override
public String getName() {
return "部门初始化";
}
@Override
public void execute() {
log.info("开始初始化部门数据...");
if (departmentService.count() > 0) {
log.info("部门数据已存在,跳过初始化");
return;
}
// 创建默认部门
DepartmentEntity dept = new DepartmentEntity();
dept.setDeptName("总经办");
dept.setParentId(0L);
departmentService.save(dept);
log.info("部门初始化完成");
}
}
五、关键方法说明
| 方法 | 说明 | 是否必须实现 |
|---|---|---|
getName() |
返回初始化器名称 | 是 |
execute() |
执行初始化逻辑 | 是 |
onStart() |
初始化开始前的回调 | 否 |
onEnd(long costTime) |
初始化结束后的回调 | 否 |
doExecute() |
模板方法,调用 onStart → execute → onEnd | 内部调用 |
六、注意事项
- 幂等性:初始化逻辑应保证幂等,多次执行不产生副作用
- 异常处理:
execute()方法抛出异常时,会被捕获并记录到失败列表,但不影响其他初始化器执行 - 顺序依赖:通过
@Order注解控制初始化顺序,确保依赖的数据先被初始化 - 日志记录:在关键节点记录日志,便于排查问题
- Component 注解:必须添加
@Component注解,否则不会被 Spring 扫描到
七、现有初始化器参考
项目中已有的初始化器:
| 初始化器 | 顺序 | 说明 |
|---|---|---|
DepartmentInitializer |
1 | 部门数据初始化 |
RoleInitializer |
2 | 角色数据初始化 |
UserInitializer |
无 | 用户数据初始化 |
附录:特殊初始化方式
ApplicationReadyEvent(仅特殊场景使用)
在某些特殊场景下(如打印元数据初始化),需要在程序启动后自动执行初始化,可使用 @EventListener 注解:
@Configuration
public class PrintAutoConfiguration {
@Bean
public PrintInitialization printInitialization(...) {
return new PrintInitialization(...);
}
@EventListener({ApplicationReadyEvent.class})
public void init() {
PrintInitialization printInit = SpringContextHolder.getBean(PrintInitialization.class);
printInit.init();
}
}
注意:这种方式仅限于框架级别的自动初始化,业务数据初始化应使用 AbstractInitializer 方式。