Java后端开发——分层解耦详解

文章目录

    • 一、三层架构
      • [1.1 概述](#1.1 概述)
      • [1.2 具体实现方法](#1.2 具体实现方法)
    • 二、分层解耦
      • [2.1 以往问题](#2.1 以往问题)
      • [2.2 概念解释](#2.2 概念解释)
      • [2.3 解耦思路](#2.3 解耦思路)
    • [三、Spring核心:IOC & DI](#三、Spring核心:IOC & DI)
      • [3.1 快速入门](#3.1 快速入门)
      • [3.2 IOC(控制反转)详解](#3.2 IOC(控制反转)详解)
      • [3.3 DI(依赖注入)详解 注入方式](#3.3 DI(依赖注入)详解 注入方式)

标签:JavaWeb、三层架构、分层解耦、Spring、IOC、DI

一、三层架构

1.1 概述

为什么要采用三层架构?

  • 遵循单一职责原则,便于代码复用和后期维护。
  • 在程序设计和开发时,让每一个接口、类、方法的职责尽可能单一。
  • 代码拆分为以下三层:
    • controller :控制层,接收前端请求,处理请求并响应数据。
    • service :业务逻辑层,处理具体业务逻辑。
    • dao :数据访问层(Data Access Object,持久层),负责数据的增删改查。

1.2 具体实现方法

在 service 和 dao 层中,通常会先定义接口(命名规范为对象名+Service/Dao),再用实现类(命名规范为接口名+Impl)去实现接口,最后通过调用方法进行业务设计。


二、分层解耦

2.1 以往问题

  • 直接用 new 创建对象,业务变更时需要频繁更换对象,导致各层级耦合度高,影响维护与扩展。

2.2 概念解释

  • 耦合 :衡量软件各层/模块之间的依赖关联程度。
  • 内聚 :模块内部各功能之间的联系。
  • 高内聚低耦合 :高内聚指模块内部联系紧密,低耦合指模块之间依赖越低越好。
    高内聚、低耦合的目标是提升程序模块的可重用性和移植性,因此需要解耦。

2.3 解耦思路

  • 将项目中的类交由 IOC 容器管理(控制反转,IOC)。
  • 应用运行时需要对象时,直接依赖容器提供(依赖注入,DI)。

三、Spring核心:IOC & DI

3.1 快速入门

  • Dao 和 Service 层实现类加 @Component 注解,交由 IOC 容器管理。
  • Controller 和 Service 层通过 @Autowired 注入依赖对象。

3.2 IOC(控制反转)详解

Spring 框架为更好地标识 bean 所属层次,提供了 @Component 及其衍生注解:

注解 说明 位置
@Component 声明bean的基础注解 不属于以下三类时,用此注解
@Controller @Component的衍生注解 标注在控制层类上
@Service @Component的衍生注解 标注在业务层类上
@Repository @Component的衍生注解 标注在数据访问层类上(由于与mybatis整合,用的少)

示例:

Service 层

java 复制代码
@Service  
public class UserServiceImpl implements UserService {  
    @Autowired  
    private UserDao userDao;  
    @Override  
    public List<User> findAll(){  
        List<String> lines = userDao.findAll();  
        List<User> users = lines.stream().map(line -> {  
            String[] s1 = line.split(",");  
            String ID = s1[0];  
            String username = s1[1];  
            Integer password = Integer.parseInt(s1[2]);  
            String name= s1[3];  
            Integer age = Integer.parseInt(s1[4]);  
            LocalDateTime updateTime = LocalDateTime.parse(s1[5], DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));  
            return new User(ID,username,password,name,age,updateTime);  
        }).collect(Collectors.toList());  
        return users;  
    }  
}

Dao 层

java 复制代码
@Repository  
public class UserDaoImpl implements UserDao {  
    @Override  
    public List<String> findAll() {  
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("user.txt");  
        ArrayList<String> lines = IoUtil.readLines(resourceAsStream, StandardCharsets.UTF_8, new ArrayList<>());  
        return lines;  
    }  
}

注意:

  • 声明 bean 时可通过 value 属性指定 bean 名,未指定则为类名首字母小写。
  • 控制器 bean 只能用 @Controller 注解。
  • @ComponentScan 注解(包含在 @SpringBootApplication 中)会自动扫描启动类所在包及其子包。

3.3 DI(依赖注入)详解 注入方式

  • 属性注入

    java 复制代码
    @Autowired 
    private UserService userService;
    • 优点:简洁高效
    • 缺点:隐藏依赖关系,可能破坏封装性
  • 构造函数注入

    java 复制代码
    @Autowired 
    public UserController(UserService userService) { 
        this.userService = userService; 
    }
    • 优点:依赖关系清晰,安全性高(可用final)
    • 缺点:代码稍繁琐,参数多时臃肿
    • 注意:只有一个构造函数时, @Autowired 可省略
  • Setter方法注入

    java 复制代码
    @Autowired 
    public void setUserService(UserService userService) {
    this.userService = userService; 
    }
    • 优点:封装性好,依赖关系清晰
    • 缺点:需额外编写Set方法,代码量大
      实际开发中,属性注入和构造函数注入最常用,官方推荐构造函数注入。
      多个 Bean 对象注入的解决方案
  • @Primary :指定默认实现

    java 复制代码
    @Primary
    @Service
    public class UserServiceImpl implements UserService {}
  • @Qualifier :指定注入的 bean 名称,需配合 @Autowired

    java 复制代码
    @Qualifier("userServiceImpl")
    @Autowired
    private UserService userService;
  • @Resource :按 bean 名称注入

    java 复制代码
    @Resource(name = "userServiceImpl")
    private UserService userService;
相关推荐
颜如玉16 分钟前
🤲🏻🤲🏻🤲🏻临时重定向一定要能重定向🤲🏻🤲🏻🤲🏻
java·http·源码
程序员的世界你不懂2 小时前
【Flask】测试平台开发,新增说明书编写和展示功能 第二十三篇
java·前端·数据库
星空寻流年2 小时前
设计模式第一章(建造者模式)
java·设计模式·建造者模式
lingchen19062 小时前
MATLAB的数值计算(三)曲线拟合与插值
开发语言·matlab
gb42152872 小时前
java中将租户ID包装为JSQLParser的StringValue表达式对象,JSQLParser指的是?
java·开发语言·python
一朵梨花压海棠go2 小时前
html+js实现表格本地筛选
开发语言·javascript·html·ecmascript
曾经的三心草3 小时前
Python2-工具安装使用-anaconda-jupyter-PyCharm-Matplotlib
android·java·服务器
蒋星熠3 小时前
Flutter跨平台工程实践与原理透视:从渲染引擎到高质产物
开发语言·python·算法·flutter·设计模式·性能优化·硬件工程
Metaphor6923 小时前
Java 高效处理 Word 文档:查找并替换文本的全面指南
java·经验分享·word
ChinaRainbowSea3 小时前
7. LangChain4j + 记忆缓存详细说明
java·数据库·redis·后端·缓存·langchain·ai编程