springboot入门-业务逻辑核心service层
在 Spring Boot 中,Service 层是业务逻辑的核心,负责协调数据访问层(Repository 或 Mapper)和控制器层(Controller),处理业务规则、事务管理以及数据转换。以下是 Service 层的详细说明、常用注解及依赖注入方式:
1. Service 层的核心作用
- 业务逻辑处理:封装复杂的业务规则(如订单创建、用户权限校验)。
- 事务管理:通过
@Transactional
注解确保数据库操作的原子性。 - 异常处理:统一捕获并处理数据访问层的异常(如
DataAccessException
)。 - DTO 转换:将实体类(Entity)转换为数据传输对象(DTO),避免暴露敏感字段。
2. Service 层的常用注解
(1) @Service
- 作用:
将类标记为 Spring 管理的业务逻辑组件,自动注册为 Bean,供其他层(如 Controller)注入使用。 - 位置:类声明上方。
- 示例:
@Service public class UserService {// 业务方法... }
(2) @Transactional
- 作用:
声明方法或类需要 事务管理。如果方法抛出异常(默认RuntimeException
),事务将回滚。 - 关键参数:
参数 作用 示例 rollbackFor
指定触发回滚的异常类型 @Transactional(rollbackFor = Exception.class)
propagation
事务传播行为(如 REQUIRED
、REQUIRES_NEW
)@Transactional(propagation = Propagation.REQUIRED)
isolation
事务隔离级别(如 READ_COMMITTED
)@Transactional(isolation = Isolation.READ_COMMITTED)
- 示例:
@Service public class OrderService {@Transactional // 方法级事务public void createOrder(Order order) {// 业务逻辑...} }
3. 如何将 Repository/Mapper 注入到 Service?
在 Spring Boot 中,通过 依赖注入(Dependency Injection, DI) 将 Repository 或 Mapper 注入到 Service。以下是两种常用方式:
(1) 构造器注入(推荐)
- 原理:通过构造函数传递依赖,Spring 自动注入 Bean。
- 优点:
- 明确依赖关系,避免
NullPointerException
。 - 支持不可变(
final
)字段,线程安全。
- 明确依赖关系,避免
- 示例:
@Service public class UserService {private final UserRepository userRepository;// 构造器注入(Spring 4.3+ 可省略 @Autowired)public UserService(UserRepository userRepository) {this.userRepository = userRepository;}public User getUserById(Long id) {return userRepository.findById(id).orElse(null);} }
(2) @Autowired
注解注入
- 原理:通过字段或 Setter 方法自动注入依赖。
- 缺点:
- 字段注入可能导致循环依赖问题。
- Setter 注入不够直观。
- 示例:
@Service public class UserService {@Autowired // 字段注入(不推荐)private UserRepository userRepository;// 或 Setter 注入@Autowiredpublic void setUserRepository(UserRepository userRepository) {this.userRepository = userRepository;} }
4. 完整示例:Service 层工作流程
(1) 实体类(Model)
@Entity
@Table(name = "users")
public class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String name;private String email;// Getter & Setter
}
(2) Repository 接口(JPA)
public interface UserRepository extends JpaRepository<User, Long> {User findByEmail(String email);
}
(3) Service 类
@Service
public class UserService {private final UserRepository userRepository;public UserService(UserRepository userRepository) {this.userRepository = userRepository;}@Transactionalpublic User createUser(String name, String email) {User user = new User();user.setName(name);user.setEmail(email);return userRepository.save(user); // 调用 Repository 保存数据}public User getUserByEmail(String email) {return userRepository.findByEmail(email);}
}
(4) Controller 类
@RestController
@RequestMapping("/api/users")
public class UserController {private final UserService userService;public UserController(UserService userService) {this.userService = userService;}@PostMappingpublic User createUser(@RequestBody UserRequest request) {return userService.createUser(request.getName(), request.getEmail());}@GetMapping("/{email}")public User getUser(@PathVariable String email) {return userService.getUserByEmail(email);}
}
5. 常见问题解答
(1) 为什么推荐构造器注入?
- 不可变性:字段标记为
final
,避免中途修改。 - 依赖明确:一眼看出 Service 需要哪些依赖。
- 避免循环依赖:构造器注入在启动时就能发现循环依赖问题。
(2) @Transactional
应该加在 Service 还是 Repository?
- 推荐加在 Service 层:
Service 方法可能涉及多个 Repository 操作,需统一事务管理(如用户注册时同时操作User
表和Account
表)。
(3) 如何处理多个数据源或 Mapper(MyBatis)?
- MyBatis 的 Mapper 注入:
使用@MapperScan
扫描 Mapper 接口,然后直接注入:@Service public class OrderService {private final OrderMapper orderMapper;public OrderService(OrderMapper orderMapper) {this.orderMapper = orderMapper;} }
总结
组件 | 职责 | 核心注解 | 依赖注入方式 |
---|---|---|---|
Service | 处理业务逻辑、事务管理 | @Service , @Transactional | 构造器注入(推荐) |
Repository | 数据访问操作(JPA) | 无(继承 JpaRepository ) | 自动注入到 Service |
Mapper | 数据访问操作(MyBatis) | @Mapper (MyBatis) | 自动注入到 Service |
通过合理使用 @Service
和 @Transactional
,结合构造器注入,可以构建清晰、可维护的 Service 层,高效管理业务逻辑和数据库事务。