当前位置: 首页 > news >正文

深入理解java web分层架构的高内聚低耦合

在软件开发中,构建一个高效、可维护且可扩展的应用系统一直是开发者追求的目标。分层架构依赖注入(IOC)是实现这一目标的重要策略。本文将深入探讨三层架构的高内聚特性、低耦合的设计原则,以及如何通过IOC(控制反转)技术来进一步提升应用的灵活性和可维护性。

一、三层架构的含义

三层架构是一种常见的软件设计模式,它将应用程序分为三个主要的逻辑层:表示层(请求层)、业务逻辑层(业务处理层)和数据访问层(数据层)。每个层都有特定的职责,这样设计可以提高系统的可维护性、可扩展性和可复用性。具体介绍如下:
在这里插入图片描述

  1. 请求层(controller):

    请求层是系统与外部交互的接口,负责接收用户的请求或其他系统的调用。

  2. 业务逻辑层:

    这一层主要包含系统的核心业务规则和处理逻辑。它接收来自请求层的请求,进行业务处理和数据加工,然后将结果返回给请求层。

  3. 数据访问层:
    数据访问层主要负责与数据库或其他数据源进行交互,实现数据的存储和读取。它将业务逻辑层的抽象数据操作转换为具体的数据库操作。
    ·

@RestControllerpublic class UserController {@GetMapping("/getUser")public String getUser(@RequestParam("userId") int userId) {// 将 userId 传递给服务层进行处理return "请求已接收,即将传递给服务层处理 userId: " + userId;}}

二、三层架构的高内聚

高内聚意味着每个层次内部的功能紧密相关,具有明确的职责和功能边界。
请求层只负责处理客户端发来的网络请求,业务层是负责实现业务逻辑,数据层只负责读取存储数据。

三、三层架构的低耦合

低耦合意味着各个层次之间的依赖关系尽可能地减少,相互之间的影响降到最低
比如服务层的serverA换成了serverB,只用更改服务层的代码,不用修改请求层的代码,这就是低耦合。spring项目通过IOC来实现低耦合性
四、IOC 容器
IOC(Inversion of Control,控制反转)容器是一种用于管理对象创建和依赖关系的工具。
在这里插入图片描述

解耦对象的创建和使用:在传统的软件开发中,对象的创建通常由使用它的代码直
接负责。而在 IOC 容器中,对象的创建和生命周期管理由容器负责,使用对象的
代码只需要从容器中获取所需的对象即可,大大降低了代码之间的耦合度。方便依
赖注入:IOC 容器能够自动将对象之间的依赖关系注入到需要的对象中,使得对象
之间的依赖关系更加清晰和易于管理。

在 Spring 框架里,Spring 容器属于典型的 IOC 容器。举个例子,对于一个订单服
务接口(OrderService),它存在两个实现类(serviceA 与 serviceB)。倘若没有
IOC 容器,那么 controller 类或许就得自行创建相应订单实现类的实例。然而,在
Spring IOC 容器的环境下,仅需在 controller 类中运用依赖注入(比如借助
@Autowired 注解)订单服务接口,并且在对应的实现类上添加 @Service 注解,
Spring 容器便会自动把订单服务实现类的实例注入到 controller 之中。

以下示例代码:

  1. 首先创建订单服务接口 OrderService
public interface OrderService {void processOrder();
}
  1. 创建两个实现类 ServiceAServiceB

ServiceA.java

import org.springframework.stereotype.Service;public class ServiceA implements OrderService {@Overridepublic void processOrder() {System.out.println("ServiceA is processing the order.");}
}

ServiceB.java

import org.springframework.stereotype.Service;@Service
public class ServiceB implements OrderService {@Overridepublic void processOrder() {System.out.println("ServiceB is processing the order.");}
}
  1. 创建 Controller
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class OrderController {@Autowiredprivate OrderService orderService;@GetMapping("/processOrder")public void handleOrder() {orderService.processOrder();}
}

在上述代码中,@Service 注解用于将 ServiceA 标记为 Spring 管理的服务类。在 OrderController 中,通过 @Autowired 注解实现了对 OrderService 的依赖注入,Spring 容器会根据具体的配置和扫描自动选择合适的实现类注入到 Controller 中。
如果订单服务实现类换成了ServiceB,只用将@Service 注解加到ServiceB上

五、IOC注意事项

  1. 当某个包与启动程序不在同一个包时使用 @ComponentScan
    例子:假设项目的启动类位于 com.example.main 包中,而一些自定义的组件位于 DAO 包中。如果不使用 @ComponentScan 指定包含自定义组件的包,Spring 容器将无法自动扫描和注册这些组件。
    在这里插入图片描述

    代码示例:

@MapperScan({"com.example.springboot","DAO"})
@EnableScheduling
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
public class MainApplication {public static void main(String[] args) {SpringApplication.run(MainApplication.class, args);}}    
  1. @Autowired 介绍及遇到多个同类型 bean 的解决方案:

    @Autowired 是 Spring 框架中用于自动装配(依赖注入)的注解。它会根据类型自动在 Spring 容器中查找匹配的 bean 并注入到目标对象中。在刚才那个订单服务例子中,有两个订单服务类,如果ServiceA和ServiceB都注入IOC容器内,程序运行时将会报错,因为这个两个都继承了OrderService接口他们的bean类型相同。

    当遇到多个同类型 bean 的情况时,可以使用以下解决方案:

    @Primary:为某个 bean 添加 @Primary 注解,提高其优先级,确保在注入时优先选择该 bean。
    例子:假设有两个 UserRepository 的实现类 UserRepositoryImpl1UserRepositoryImpl2,如果希望 UserRepositoryImpl1 优先被注入,可以在 UserRepositoryImpl1 上添加 @Primary 注解:
    java @Repository @Primary public class UserRepositoryImpl1 implements UserRepository { // 实现方法 }

    @Qualifier("beanName"):在 @Autowired 注解上面添加 @Qualifier 注解,并指定 bean 的名称,可以精确地选择要注入的 bean。
    例子:
    java @Service public class UserService { @Autowired @Qualifier("userRepositoryImpl2") private UserRepository userRepository; // 其他业务方法 }

    @Resource(name = ''):这也是一种指定 bean 名称进行注入的方式,与 @Qualifier 类似。
    例子:
    java @Service public class UserService { @Resource(name = "userRepositoryImpl2") private UserRepository userRepository; // 其他业务方法 }

总之,三层架构结合 IOC 容器和合理的依赖注入技术,能够构建出结构清晰、易于维护和扩展的软件系统。在实际开发中,我们需要根据项目的具体需求和特点,灵活运用这些技术和设计模式,以提高软件的质量和开发效率。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 力扣热题100_二分查找_74_搜索二维矩阵
  • WPF学习(8) --Windows API函数的使用
  • SSM环保知识普及平台—计算机毕业设计源码20330
  • JavaScript AI 编程助手
  • 回顾 | 瑞云科技亮相ICIC2024,虚拟仿真实训云平台引关注
  • 下载文件--后端返回文件数据,前端怎么下载呢
  • 论文阅读笔记:The Graph Neural Network Model
  • 微信小程序电话号码授权
  • 机器学习第十一章-特征选择与稀疏学习
  • Vue3.0生命周期钩子(包含:Vue 2.0 和 Vue 3.0)
  • JavaEE 的相关知识点(一)
  • [000-002-01].数据库调优相关学习
  • python提取b站视频的音频(提供源码
  • 华为---端口隔离简介和示例配置
  • 牛客周赛 Round 56
  • 自己简单写的 事件订阅机制
  • 【347天】每日项目总结系列085(2018.01.18)
  • 03Go 类型总结
  • 30天自制操作系统-2
  • CSS进阶篇--用CSS开启硬件加速来提高网站性能
  • Fundebug计费标准解释:事件数是如何定义的?
  • Js基础——数据类型之Null和Undefined
  • JS数组方法汇总
  • Laravel5.4 Queues队列学习
  • Perseus-BERT——业内性能极致优化的BERT训练方案
  • 安卓应用性能调试和优化经验分享
  • 案例分享〡三拾众筹持续交付开发流程支撑创新业务
  • 短视频宝贝=慢?阿里巴巴工程师这样秒开短视频
  • 计算机在识别图像时“看到”了什么?
  • 前端_面试
  • 数组的操作
  • 赢得Docker挑战最佳实践
  • 阿里云ACE认证之理解CDN技术
  • ​LeetCode解法汇总2182. 构造限制重复的字符串
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (SpringBoot)第七章:SpringBoot日志文件
  • (webRTC、RecordRTC):navigator.mediaDevices undefined
  • (附源码)流浪动物保护平台的设计与实现 毕业设计 161154
  • (介绍与使用)物联网NodeMCUESP8266(ESP-12F)连接新版onenet mqtt协议实现上传数据(温湿度)和下发指令(控制LED灯)
  • (转)项目管理杂谈-我所期望的新人
  • **《Linux/Unix系统编程手册》读书笔记24章**
  • .NET C# 操作Neo4j图数据库
  • .NET C# 使用 SetWindowsHookEx 监听鼠标或键盘消息以及此方法的坑
  • .net core IResultFilter 的 OnResultExecuted和OnResultExecuting的区别
  • .net framwork4.6操作MySQL报错Character set ‘utf8mb3‘ is not supported 解决方法
  • .net/c# memcached 获取所有缓存键(keys)
  • .net反编译工具
  • :“Failed to access IIS metabase”解决方法
  • @Valid和@NotNull字段校验使用
  • [ 隧道技术 ] cpolar 工具详解之将内网端口映射到公网
  • [12] 使用 CUDA 进行图像处理
  • [2013][note]通过石墨烯调谐用于开关、传感的动态可重构Fano超——
  • [2016.7 Day.4] T1 游戏 [正解:二分图 偏解:奇葩贪心+模拟?(不知如何称呼不过居然比std还快)]
  • [20180129]bash显示path环境变量.txt
  • [AI aider] 打造终端AI搭档:Aider让编程更智能更有趣!