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

​

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

一、三层架构的含义

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

  1. 请求层(controller):

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

  2. 业务逻辑层:

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

  3. 数据访问层:

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

    ·

java 复制代码
    @RestController
    public 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:
java 复制代码
public interface OrderService {
    void processOrder();
}
  1. 创建两个实现类 ServiceA 和 ServiceB:

ServiceA.java:

java 复制代码
import org.springframework.stereotype.Service;


public class ServiceA implements OrderService {
    @Override
    public void processOrder() {
        System.out.println("ServiceA is processing the order.");
    }
}

ServiceB.java:

java 复制代码
import org.springframework.stereotype.Service;

@Service
public class ServiceB implements OrderService {
    @Override
    public void processOrder() {
        System.out.println("ServiceB is processing the order.");
    }
}
  1. 创建 Controller:
java 复制代码
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 {

    @Autowired
    private 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 容器将无法自动扫描和注册这些组件。

    代码示例:

java 复制代码
@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 的实现类 UserRepositoryImpl1 和 UserRepositoryImpl2,如果希望 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 容器和合理的依赖注入技术,能够构建出结构清晰、易于维护和扩展的软件系统。在实际开发中,我们需要根据项目的具体需求和特点,灵活运用这些技术和设计模式,以提高软件的质量和开发效率。

相关推荐
代码山河1 小时前
Python就业方向全解析:后端、爬虫、数据分析、AI你选哪个?
python·学习·架构·教程·面向对象·项目
学长毕设2 小时前
基于SpringBoot的实验室资产管理系统
java·spring boot·后端
微订校园外卖平台3 小时前
校园外卖平台选模板还是定制:架构、数据流与验收清单
大数据·架构·外卖系统·本地生活·微订
zzu123zsw3 小时前
从臃肿的模板调用到声明式契约:深入 UniHttp 动态代理与多渠道生命周期扩展
java·spring boot·microsoft·unihttp
源码集结号4 小时前
云诊所门诊系统源码,基于SpringBoot+Vue.js架构,支持多租户设计与Docker容器化部署
java·spring boot·源码·医院信息系统·门诊系统·诊所系统
论文复现现场4 小时前
WRF、FEA 能用 L40S 加速吗?求解器检查、断点恢复与长期运行
java·数据库·算法·wrf·有限元分析·gpu计算·断点续算
ZhengEnCi4 小时前
用 AI 写代码为什么拼到最后还是拼人:算力瓶颈与领域专家提示词的本质差异
算法·架构
啃瓜子的松鼠4 小时前
泛微OAe9-后端二开异步调用
java
Decay__5 小时前
04_MySQL DBA 日常运维手册 —— 会话管理、锁与阻塞、事务监控、慢查询与日志巡检
运维·数据库·sql·mysql·架构
秋天的怀念_David5 小时前
第二十一夜 · 数字黑洞与西西弗斯的惩罚
java·程序人生·算法