Spring Boot为何查询走Service、保存直接调Repository?CRUD默认实现?
Spring Boot分层架构常见问题解答
分层架构示例代码
Repository层
@Repository public interface CarRepository extends JpaRepository<Car, Long> { // 注:findById方法JpaRepository已自带默认实现,此处无需重复定义 Optional<Car> findById(Long id); }
Service接口
public interface CarService { Optional<Car> findById(Long id); }
Service实现类
@Service @Transactional @Slf4j @RequiredArgsConstructor public class CarServiceImpl implements CarService { private final CarRepository carRepository; @Override public Optional<Car> findById(Long id) { return carRepository.findById(id); } }
Controller层(示例写法)
@RestController @RequestMapping("/") @RequiredArgsConstructor public class CarController { @Autowired private final CarService carService; // GET ONE CAR @GetMapping("/{id}") public ResponseEntity<Optional<Car>> find(@PathVariable Long id) { return ResponseEntity.ok() .header("Custom-Header", "foo") .body(carService.findById(id)); } // 不规范的保存写法:直接调用Repository @Autowired private final CarRepository carRepository; // SAVE ONE CAR @PostMapping("/") Car newCar(@RequestBody Car car) { return carRepository.save(car); } }
问题解答
1. 为何查询实体时通过Service实现类调用,而保存实体时直接访问Repository?
这种写法属于不规范的分层架构实现,本质是没严格遵循职责分离的设计原则:
- Repository层的职责是封装数据库访问逻辑,只做和数据库的直接交互;
- Service层是业务逻辑的核心载体,所有业务操作(查询、保存、修改、删除)都应该统一通过Service层对外提供。
示例里直接在Controller调用Repository的做法,会导致后续如果要加业务规则(比如保存前校验数据合法性、记录操作日志、补充事务控制逻辑),必须修改Controller层代码,违背了开闭原则。正确的做法是在CarService中新增save方法,在CarServiceImpl中实现该方法(内部调用Repository的save),Controller只调用Service层的save方法。
2. 是否有部分CRUD方法具备默认实现?
是的,Spring Data JPA的JpaRepository接口继承了CrudRepository和PagingAndSortingRepository,已经内置了一系列CRUD操作的默认实现,比如:
save(T entity):保存/更新实体findById(ID id):根据ID查询实体findAll():查询所有实体deleteById(ID id):根据ID删除实体
示例中的CarRepository里手动定义的findById(Long id)其实是多余的,直接继承JpaRepository就可以直接使用该方法。
内容的提问来源于stack exchange,提问作者Al Grant
相关产品推荐
相关产品推荐

