在Service层反射调用其他Service层的方法 , 却发现原先@Autowired注入的Dao层为null

本文探讨了在Spring环境下,Service层通过反射调用其他Service层方法时,@Autowired注解失效的问题。原因是反射创建的对象未被Spring容器管理。解决方案是通过工具类获取Spring Bean,确保对象在容器内,从而保证依赖注入正常工作。示例代码展示了修改前后的对比,以及如何正确地从容器中获取并调用方法。

问题:

在Service层反射调用其他Service层的方法 , 调试时发现原先@Autowired注入的Dao层为null。

原因:

这是因为反射获得的类没有交给Spring容器管理,以至于@Autowired失效。

修改前的代码:

private String getResult(String methodParam, String methodName) throws Exception {
   
   
    Class<BatchWaybillServiceImpl> bat
<think> 我们正在讨论的是在JavaService中,应该调用其他Service方法还是直接调用DAO方法。根据引用内容,我们可以总结以下几点: 1. 引用[1]提到,Service直接调用DAO可能会违背MVC模式的概念,增加代码耦合性。如果直接调用DAO,那么业务逻辑处理应该放在哪里?如果写在DAO,当业务需求改变时,可能需要修改DAO,增加工作量,且代码重用性不高。因此,建议Service调用其他Service。 2. 引用[2]和引用[3]提到了在非Spring管理的地方(如Servlet、main方法调用DAOService的问题,这提醒我们调用关系应该是在Spring容器管理的Bean之间进行,通常通过依赖注入实现。 3. 引用[4]展示了一个Service通过反射调用其他Service方法时遇到的问题:由于通过反射创建Service实例(new BatchWaybillServiceImpl())而不是由Spring容器管理,导致其中注入DAOnull。这进一步说明了应该通过Spring容器来管理Bean之间的依赖关系。 根据上述引用和实际开发规范,我们可以得出以下结论: - 在Service中,应该优先调用其他Service方法,而不是直接调用DAO。因为Service是业务逻辑的封装,一个业务操作可能涉及多个数据表的操作,而这些操作可能已经封装在其他Service中。直接调用其他Service可以复用业务逻辑,避免代码重复,并且符合分设计原则(Service依赖于其他Service,而不是直接依赖DAO)。 - 直接调用DAO的情况:当当前Service需要执行一个非常简单的数据访问操作,且该操作没有在其他Service中封装,或者该操作仅与当前ServiceDAO相关,且不涉及其他业务逻辑时,可以直接调用自己的DAO。 但是,需要注意的是,如果在一个Service调用一个Service方法,要特别注意事务的传播行为。Spring的事务管理是基于AOP代理的,在同一个类中调用一个方法(即使是事务方法)是不会触发事务的。因此,如果两个Service方法需要在同一事务中,应该将它们放在同一个Service类中,或者通过注入自身代理(使用AopContext)来调用,但更推荐将事务方法放在不同的Service中,并通过Spring的事务传播机制来控制。 总结选择方法: 1. **调用其他Service的情况**: - 需要复用其他Service中已经存在的业务逻辑。 - 操作涉及多个数据表,且这些操作已经被其他Service封装。 - 需要确保跨多个Service的操作在同一个事务中(通过声明式事务管理)。 2. **直接调用DAO的情况**: - 当前Service需要执行简单的CRUD操作,且这些操作不涉及其他业务逻辑。 - 当前ServiceDAO方法仅被当前Service使用,且没有复用价值。 外,要避免在Service中绕过Service直接调用其他ServiceDAO(即调用其他模块的DAO),因为这破坏了模块的封装性,会导致代码高度耦合。 因此,在编写Service方法时,应优先考虑调用其他Service,只有在上述直接调用DAO的情况满足时,才考虑直接调用自己的DAO。 相关问题: 1. Service调用其他Service调用DAO的主要区别是什么? 2. 在Service中直接调用DAO有哪些潜在的风险? 3. 如何确保在Service调用其他Service方法时的事务一致性? </think> 在 Java Service 方法中,选择调用其他 Service 还是直接调用 DAO,需要根据业务场景和架构规范综合判断。以下是决策依据和最佳实践: ### 一、优先调用其他 Service 的场景 ✅ 1. **存在业务逻辑复用** - 当目标操作已封装业务规则(如订单状态校验、库存扣减等)时,应调用对应 Service - 示例:支付服务需调用订单服务的 `validateOrderStatus()` 方法[^1] ```java // PaymentService.java @Autowired private OrderService orderService; // 注入其他Service public void processPayment(Order order) { // 调用其他Service的业务方法 orderService.validateOrderStatus(order); // ...支付逻辑 } ``` 2. **需要事务跨表操作** - 当操作涉及多个数据表的原子性变更时,通过 Service 保障事务一致性 - 反例:直接调用多个 DAO 可能导致部分成功/部分失败 ```java // 正确:通过OrderService管理事务 @Transactional public void createOrder(Order order) { orderDao.insert(order); inventoryDao.deductStock(order.getItems()); // 在同一个事务中 } ``` 3. **遵循分架构原则** - Service 应作为业务逻辑的协调DAO 仅负责基础数据访问[^1] - 架构关系:`Controller -> Service A -> Service B -> DAO` ### 二、可直接调用 DAO 的场景 ⚠️ 1. **简单数据操作** - 当仅需基础 CRUD 且无业务规则时(如根据ID查询用户) ```java // UserService.java @Autowired private UserDao userDao; // 直接注入DAO public User getUserById(Long id) { return userDao.selectById(id); // 直接调用DAO } ``` 2. **私有数据访问** - 当数据操作仅限当前 Service 内部使用,无需跨服务复用时 ### 三、核心决策原则 1. **避免级穿透** ▸ 禁止 `Service A → DAO B`(跨模块直连) ▸ 应改为 `Service A → Service B → DAO B`[^1] 2. **事务边界控制** ```mermaid graph LR A[Service方法] -- 需要跨表事务 --> B[调用其他Service] A -- 单表操作 --> C[直接调用DAO] ``` 3. **依赖方向** ▸ 高模块可依赖低模块(ServiceDAO) ▸ 同模块可相互调用ServiceService) ▸ 禁止反向依赖(DAOService) ### 四、典型错误案例 1. **Service 中 new 其他 Service 实例**(导致依赖注入失效)[^4] ```java // 错误:通过new创建导致@Autowired失效 OrderService orderService = new OrderService(); orderService.validate(order); // 内部DAOnull! ``` 2. **Controller 直接调用 DAO**(破坏分架构)[^2] ```java // Servlet中错误示例 public class OrderServlet extends HttpServlet { // 无法通过@Autowired注入DAO public void doGet() { UserDao userDao = new UserDao(); // 耦合严重 } } ``` ### 五、最佳实践总结 | 场景 | 调用方式 | 原因说明 | |---------------------------|-------------------|-----------------------------| | 需要复用业务逻辑 | 其他Service | 避免逻辑重复实现[^1] | | 跨实体/跨表操作 | 其他Service | 保障事务一致性 | | 简单数据查询(单表) | 直接DAO | 减少调用链开销 | | 当前Service私有数据操作 | 直接DAO | 无需服务暴露 | | 第三方服务集成 | 专用Adapter Service | 隔离外部变化 | > 💡 **黄金准则**:将 Service 视为业务能力的提供者,DAO 视为数据机械操作者。当操作蕴含业务含义时(如“冻结账户”),必调用对应 Service;当仅是数据搬运时(如“按ID查询”),可直接调用 DAO
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值