snap-user/docs/SNAPSHOT_APPROACH_COMPARISO...

10 KiB
Raw Blame History

快照功能实现方案对比

概述

本文档对比了三种不同的快照功能实现方案,从侵入性、自动化程度、维护性等角度进行分析。

方案对比

方案1方法签名模式拦截推荐

特点

  • 完全自动化:通过方法签名模式自动识别和拦截
  • 零侵入性:现有业务代码完全无需修改
  • 智能识别:支持多种命名规范

实现方式

@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) {
        // 自动创建快照
    }
}

业务代码(完全原样)

@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;
    }
}

优势

  • 完全自动化,无需修改业务代码
  • 零侵入性,保持代码原样
  • 智能识别,支持多种命名规范
  • 易于扩展和维护
  • 性能开销小

劣势

  • ⚠️ 需要了解AOP切面机制
  • ⚠️ 方法签名模式需要精心设计

方案2注解方案

特点

  • 声明式:通过注解明确声明快照行为
  • 可定制化:可以针对不同方法设置不同策略
  • 意图明确:代码中明确表达了快照意图

实现方式

@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) {
        // 根据注解配置处理快照逻辑
    }
}

业务代码(需要添加注解)

@Service
public class UserManagementService {
    
    @SnapshotAware(operation = SnapshotAware.OperationType.QUERY)
    public User getUserById(Long id) {
        return userRepository.findById(id).orElse(null);
    }
    
    @SnapshotAware(operation = SnapshotAware.OperationType.UPDATE, createSnapshotBefore = true)
    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;
    }
}

优势

  • 意图明确,可定制化
  • 声明式编程,易于理解
  • 可以针对不同方法设置不同策略
  • 支持复杂的快照逻辑

劣势

  • 需要手动添加注解
  • 容易遗漏,忘记添加注解
  • 代码侵入性相对较高
  • 维护成本较高

方案3手动集成方案

特点

  • 传统方式:在每个方法中手动添加快照逻辑
  • 直接控制:可以精确控制每个方法的快照行为
  • 灵活性高:可以根据具体需求定制

实现方式

@Service
public class UserManagementService {
    
    @Autowired(required = false)
    private SnapshotService snapshotService;
    
    public User getUserById(Long id) {
        // 手动添加快照逻辑
        if (snapshotService != null) {
            return snapshotService.getUserWithSnapshot(id);
        }
        return userRepository.findById(id).orElse(null);
    }
    
    public User updateUser(Long id, String name, String email, String phone) {
        // 手动添加快照逻辑
        if (snapshotService != null) {
            User currentUser = snapshotService.getUserWithSnapshot(id);
            if (currentUser != null && currentUser.getSnapshotId() != null) {
                snapshotService.createSnapshot(id, "用户信息更新");
            }
        }
        
        // 原有业务逻辑
        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;
    }
}

优势

  • 直接控制,灵活性高
  • 可以精确控制每个方法的快照行为
  • 不依赖AOP机制
  • 代码逻辑清晰

劣势

  • 代码侵入性强
  • 维护困难,容易出错
  • 扩展性差
  • 重复代码多
  • 性能开销相对较大

方案选择建议

推荐方案:方法签名模式拦截

适用场景:

  • 大型项目,需要快速集成快照功能
  • 现有代码较多,不希望大幅修改
  • 团队对AOP有一定了解
  • 需要零侵入性的解决方案

理由:

  1. 完全自动化:无需修改任何业务代码
  2. 零侵入性:保持代码原样,降低风险
  3. 智能识别:支持多种命名规范
  4. 易于维护:集中管理快照逻辑
  5. 性能优秀AOP开销很小

备选方案:注解方案

适用场景:

  • 需要精确控制快照行为
  • 团队对声明式编程有偏好
  • 项目规模较小,可以接受添加注解
  • 需要复杂的快照策略

理由:

  1. 意图明确:通过注解清晰表达快照意图
  2. 可定制化:可以针对不同方法设置不同策略
  3. 易于理解:代码中明确表达了快照行为

不推荐:手动集成方案

适用场景:

  • 只有少数几个方法需要快照功能
  • 对AOP机制不熟悉
  • 需要完全控制快照逻辑

理由:

  1. 维护困难:需要在每个方法中手动添加逻辑
  2. 容易出错:容易遗漏或添加错误
  3. 扩展性差:新增方法需要重复添加逻辑
  4. 代码冗余:大量重复代码

实际应用示例

方案1方法签名模式当前实现

// 业务代码完全原样
@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;
    }
}

方案2注解方案

@Service
public class UserManagementService {
    
    @SnapshotAware(operation = SnapshotAware.OperationType.QUERY)
    public User getUserById(Long id) {
        return userRepository.findById(id).orElse(null);
    }
    
    @SnapshotAware(operation = SnapshotAware.OperationType.UPDATE, createSnapshotBefore = true)
    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;
    }
}

方案3手动集成

@Service
public class UserManagementService {
    
    @Autowired(required = false)
    private SnapshotService snapshotService;
    
    public User getUserById(Long id) {
        if (snapshotService != null) {
            return snapshotService.getUserWithSnapshot(id);
        }
        return userRepository.findById(id).orElse(null);
    }
    
    public User updateUser(Long id, String name, String email, String phone) {
        if (snapshotService != null) {
            User currentUser = snapshotService.getUserWithSnapshot(id);
            if (currentUser != null && currentUser.getSnapshotId() != null) {
                snapshotService.createSnapshot(id, "用户信息更新");
            }
        }
        
        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;
    }
}

总结

方案 侵入性 自动化程度 维护性 扩展性 性能 推荐度
方法签名模式 零侵入 完全自动化 优秀 优秀 优秀
注解方案 低侵入 半自动化 良好 良好 良好
手动集成 高侵入 手动 一般

最终推荐:方法签名模式拦截方案

该方案在保持代码原样的同时,实现了完全自动化的快照功能,是最佳的解决方案。