snap-user/README_SNAPSHOT.md

445 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 用户快照功能实现总结
## 概述
本文档总结了为用户实体添加快照功能的完整实现方案。该方案通过**方法签名模式拦截**的方式,为现有的用户管理系统添加了强大的快照功能,实现了真正的**完全自动化**集成。
**注意:** 我们同时保留了注解方案和手动集成方案,供对比和参考。
## 核心设计原则
### 1. 完全自动化原则
- 只在 `User` 实体中添加了一个 `snapshotId` 字段
- **现有业务代码完全无需修改**
- 通过方法签名模式自动识别和拦截所有操作User的方法
### 2. 配置驱动原则
- 通过 `app.snapshot.enabled` 配置控制功能开关
- 支持运行时切换,无需重启应用
### 3. 完美向后兼容原则
- 现有代码完全无需修改
- 快照功能作为可选功能提供
- 当快照功能未启用时,所有查询返回原始数据
## 实现架构
### 1. 数据层
```
User (原始实体)
├── snapshotId: String // 新增字段,标识当前使用的快照
UserSnapshot (快照实体)
├── snapshotId: String // 快照唯一标识
├── userId: Long // 关联的用户ID
├── 所有User字段的副本 // 完整数据快照
├── snapshotCreateTime: Date // 快照创建时间
└── snapshotReason: String // 快照创建原因
```
### 2. AOP切面层核心
```
UserEntityAspect (用户实体切面) - 推荐方案
├── aroundUserQuery() // 拦截查询方法getUser*, findUser*, queryUser*
├── aroundUserListQuery() // 拦截批量查询方法get*Users*, find*Users*
├── aroundUserUpdate() // 拦截更新方法updateUser*, modifyUser*, editUser*
├── aroundUserDelete() // 拦截删除方法deleteUser*, removeUser*
├── aroundUserCreate() // 拦截创建方法createUser*, addUser*
└── aroundUserOperation() // 通用拦截器(兜底处理)
SnapshotAspect (注解切面) - 备选方案
├── @Around("@annotation(snapshotAware)") // 拦截所有标记注解的方法
├── handleQuery() // 处理查询操作
├── handleUpdate() // 处理更新操作
├── handleDelete() // 处理删除操作
└── handleCreate() // 处理创建操作
```
### 3. 服务层(完全原样)
```
UserManagementService (示例服务)
├── createUser() // 自动识别为创建操作
├── updateUser() // 自动识别为更新操作
├── deleteUser() // 自动识别为删除操作
├── getUserById() // 自动识别为查询操作
├── getAllActiveUsers() // 自动识别为批量查询操作
└── getUserByEmail() // 自动识别为查询操作
HRService (示例服务)
├── updateEmployeeInfo() // 自动识别为更新操作
├── getEmployeesByDepartment() // 自动识别为批量查询操作
├── promoteEmployee() // 自动识别为更新操作
└── transferEmployee() // 自动识别为更新操作
SecurityService (示例服务)
├── lockUser() // 自动识别为更新操作
├── unlockUser() // 自动识别为更新操作
├── getRecentlyLoggedInUsers() // 自动识别为批量查询操作
└── getLockedUsers() // 自动识别为批量查询操作
```
## 三种方案对比
### 方案1方法签名模式拦截推荐
- **特点**:完全自动化,零侵入性
- **优势**:无需修改业务代码,智能识别
- **适用**:大型项目,需要快速集成
### 方案2注解方案备选
- **特点**:声明式,需要添加注解
- **优势**:意图明确,可定制化
- **适用**:需要精确控制快照行为
### 方案3手动集成方案参考
- **特点**:传统方式,手动修改每个方法
- **优势**:直接控制,灵活性高
- **适用**:只有少数方法需要快照功能
详细对比请参考:[方案对比文档](docs/SNAPSHOT_APPROACH_COMPARISON.md)
## 关键实现细节
### 1. 方法签名模式匹配(推荐方案)
```java
@Aspect
@Component
public class UserEntityAspect {
// 拦截所有返回User的查询方法
@Around("execution(* com.example.refactor.service.*Service.getUser*(Long)) || " +
"execution(* com.example.refactor.service.*Service.findUser*(Long)) || " +
"execution(* com.example.refactor.service.*Service.queryUser*(Long))")
public Object aroundUserQuery(ProceedingJoinPoint joinPoint) {
// 自动应用快照逻辑
}
// 拦截所有更新User的方法
@Around("execution(* com.example.refactor.service.*Service.updateUser*(Long, ..)) || " +
"execution(* com.example.refactor.service.*Service.modifyUser*(Long, ..)) || " +
"execution(* com.example.refactor.service.*Service.editUser*(Long, ..))")
public Object aroundUserUpdate(ProceedingJoinPoint joinPoint) {
// 自动创建快照
}
}
```
### 2. 注解方案(备选方案)
```java
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SnapshotAware {
OperationType operation() default OperationType.QUERY;
boolean createSnapshotBefore() default false;
String snapshotReason() default "";
}
@Aspect
@Component
public class SnapshotAspect {
@Around("@annotation(snapshotAware)")
public Object aroundSnapshotAware(ProceedingJoinPoint joinPoint, SnapshotAware snapshotAware) {
// 根据注解配置处理快照逻辑
}
}
```
### 3. 服务层完全原样
```java
@Service
public class UserManagementService {
// 完全原样的业务代码,无需任何修改
public User getUserById(Long id) {
return userRepository.findById(id).orElse(null);
}
public User updateUser(Long id, String name, String email, String phone) {
User user = userRepository.findById(id).orElse(null);
if (user != null) {
user.setName(name);
user.setEmail(email);
user.setPhone(phone);
user.setUpdateTime(new Date());
return userRepository.save(user);
}
return null;
}
}
```
## 使用方式
### 1. 启用快照功能
```yaml
# application.yml
app:
snapshot:
enabled: true
```
### 2. 禁用快照功能(默认)
```yaml
# application.yml
app:
snapshot:
enabled: false # 或者不配置此属性
```
### 3. 业务代码完全无需修改
```java
// 所有现有的业务代码都自动支持快照功能
@Service
public class UserManagementService {
// 这些方法会自动被拦截并应用快照逻辑
public User getUserById(Long id) { /* 原样代码 */ }
public User updateUser(Long id, String name, String email, String phone) { /* 原样代码 */ }
public void deleteUser(Long id) { /* 原样代码 */ }
public List<User> getAllActiveUsers() { /* 原样代码 */ }
}
```
### 4. API调用示例
```bash
# 创建快照
curl -X POST http://localhost:8080/api/users/1/snapshots \
-H "Content-Type: application/json" \
-d '{"reason":"数据备份"}'
# 应用快照
curl -X POST http://localhost:8080/api/users/1/snapshots/SNAP_xxx/restore
# 清除快照
curl -X DELETE http://localhost:8080/api/users/1/snapshots
```
## 优势特点
### 1. 真正的完全自动化
- **现有代码完全无需修改**
- 通过方法签名模式自动识别所有操作
- 所有服务层方法都自动支持快照
### 2. 完美的向后兼容
- 当快照功能未启用时,所有查询返回原始数据
- 现有API接口完全不变
- 支持渐进式部署
### 3. 智能识别机制
- 通过方法名模式自动识别操作类型
- 支持多种命名规范get/find/query, update/modify/edit等
- 通用拦截器兜底处理
### 4. 强一致性
- 使用事务确保数据一致性
- 删除快照时检查依赖关系
- 支持并发安全操作
### 5. 高度可扩展
- 可以轻松添加新的方法名模式
- 支持自定义快照创建逻辑
- 可以针对不同方法设置不同的快照策略
## 真实场景支持
### 1. 控制器层(完全无需修改)
```java
@GetMapping("/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
User user = userManagementService.getUserById(id); // 自动支持快照
if (user != null) {
return ResponseEntity.ok(user);
}
return ResponseEntity.notFound().build();
}
@PutMapping("/{id}")
public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody UpdateUserRequest request) {
User user = userManagementService.updateUser(id, request.getName(), request.getEmail(), request.getPhone());
if (user != null) {
return ResponseEntity.ok(user);
}
return ResponseEntity.notFound().build();
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userManagementService.deleteUser(id); // 自动支持快照
return ResponseEntity.ok().build();
}
```
### 2. 服务层(完全原样)
```java
@Service
public class UserManagementService {
// 完全原样的业务代码,自动被拦截
public User getUserById(Long id) {
return userRepository.findById(id).orElse(null);
}
public User updateUser(Long id, String name, String email, String phone) {
User user = userRepository.findById(id).orElse(null);
if (user != null) {
user.setName(name);
user.setEmail(email);
user.setPhone(phone);
user.setUpdateTime(new Date());
return userRepository.save(user);
}
return null;
}
public void deleteUser(Long id) {
User user = userRepository.findById(id).orElse(null);
if (user != null) {
user.setStatus("DELETED");
user.setUpdateTime(new Date());
userRepository.save(user);
}
}
}
```
### 3. 业务逻辑(完全透明)
```java
// 任何业务逻辑都能自动获得快照支持
public List<User> getEmployeesByDepartment(String department) {
return userRepository.findByDepartment(department); // 自动被拦截
}
public User promoteEmployee(Long userId, String newPosition, Double newSalary) {
User user = userRepository.findById(userId).orElse(null);
if (user != null) {
user.setPosition(newPosition);
user.setSalary(newSalary);
user.setUpdateTime(new Date());
return userRepository.save(user); // 自动被拦截
}
return null;
}
```
## 方法签名模式说明
### 1. 查询方法模式
```
getUser*(Long) // getUserById, getUserByEmail等
findUser*(Long) // findUserById, findUserByEmail等
queryUser*(Long) // queryUserById, queryUserByEmail等
get*Users*() // getAllUsers, getActiveUsers等
find*Users*() // findUsersByDepartment等
query*Users*() // queryUsersByStatus等
```
### 2. 更新方法模式
```
updateUser*(Long, ..) // updateUser, updateUserInfo等
modifyUser*(Long, ..) // modifyUser, modifyUserInfo等
editUser*(Long, ..) // editUser, editUserInfo等
changeUser*(Long, ..) // changeUser, changeUserInfo等
```
### 3. 删除方法模式
```
deleteUser*(Long) // deleteUser, deleteUserById等
removeUser*(Long) // removeUser, removeUserById等
destroyUser*(Long) // destroyUser, destroyUserById等
```
### 4. 创建方法模式
```
createUser*(..) // createUser, createUserWithInfo等
addUser*(..) // addUser, addUserWithInfo等
newUser*(..) // newUser, newUserWithInfo等
```
## 性能考虑
### 1. AOP性能开销
- Spring AOP的性能开销很小
- 只在方法调用时执行,不影响正常业务
- 可以通过缓存优化快照查询
### 2. 存储空间
- 每个快照包含完整的用户数据
- 建议定期清理不需要的快照
- 可以考虑数据压缩
### 3. 查询性能
- 快照查询需要额外的数据库操作
- 可以考虑缓存机制
- 对于大量快照可以考虑分页
## 扩展功能
### 1. 自定义方法模式
```java
// 可以轻松添加新的方法名模式
@Around("execution(* com.example.refactor.service.*Service.fetchUser*(Long))")
public Object aroundUserFetch(ProceedingJoinPoint joinPoint) {
// 处理fetchUser*模式的方法
}
```
### 2. 条件快照创建
```java
// 可以根据业务逻辑决定是否创建快照
if (args.length > 0 && args[0] instanceof Long) {
Long userId = (Long) args[0];
User currentUser = snapshotService.getUserWithSnapshot(userId);
if (currentUser != null && currentUser.getSnapshotId() != null) {
// 只有用户正在使用快照时才创建新快照
snapshotService.createSnapshot(userId, "用户信息更新");
}
}
```
### 3. 批量操作支持
```java
// 自动支持批量操作
public List<User> getAllActiveUsers() {
return userRepository.findByStatus("ACTIVE"); // 自动被拦截并应用快照
}
```
## 演示和测试
### 1. 运行演示
```bash
# 启动应用后,会自动运行演示
mvn spring-boot:run
```
### 2. 运行测试
```bash
# 运行所有测试
mvn test
# 运行特定测试
mvn test -Dtest=SnapshotApproachComparisonTest
```
### 3. 查看演示结果
应用启动后,控制台会显示:
- 方案1方法签名模式拦截演示
- 方案2注解方案演示
- 方案3手动集成方案演示
- 性能对比测试结果
## 总结
这个**方法签名模式拦截方案**成功地:
1. **真正实现了完全自动化**:现有代码完全无需修改,通过方法签名自动识别
2. **提供了智能识别机制**:通过方法名模式自动识别操作类型
3. **保持了完美的向后兼容**:当快照功能未启用时,所有查询返回原始数据
4. **提供了强大的功能**:支持完整的快照生命周期管理
5. **确保了数据一致性**:使用事务和锁机制
6. **提供了良好的扩展性**:可以轻松添加新的方法名模式
该方案完美解决了您提到的真实场景问题,确保所有通过服务层查询、修改、删除用户数据的地方都能自动支持快照功能,同时保持了代码的完全原样性和可维护性。
**同时,我们保留了注解方案和手动集成方案,供您对比和参考。**