【JavaWeb | 第四篇】分层解耦

目录

一、SpringBootWeb案例

二、分层解耦

[2.1 三层架构](#2.1 三层架构)

[2.2 分层解耦](#2.2 分层解耦)

[2.3 IOC&DI](#2.3 IOC&DI)

[2.3.1 IOC详解](#2.3.1 IOC详解)

[2.3.2 DI详解](#2.3.2 DI详解)


一、SpringBootWeb案例

现在有一个案例,需求是将user.txt文件中的数据返回给客户端的前端页面。

我们把读取数据、业务逻辑处理、响应数据都写到Controller层当中了。

在实际开发中如果使用这种开发方式,会有以下问题:

  • 复用性差
  • 难以维护
java 复制代码
/**
 * 用户信息Controller
 */
@RestController //@Controller + @ResponseBody -----> 如果返回的是一个对象/集合 --> 转json --> 响应
public class UserController {
    @RequestMapping("/list" )
    public List<User> list(){
        //1. 读取user.txt中的数据
        InputStream in = this.getClass().getClassLoader().getResourceAsStream("user.txt");
        ArrayList<String> lines = IoUtil.readUtf8Lines(in, new ArrayList<>());

        //2. 业务逻辑处理: 解析数据, 封装User对象 --> List<User>
        List<User> userList = lines.stream().map(line -> {
            String[] split = line.split(",");
            return new User(
                    Integer.parseInt(split[0]),
                    split[1],
                    split[2],
                    split[3],
                    Integer.parseInt(split[4]),
                    LocalDateTime.parse(split[5], DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        }).toList();

        //3. 响应数据
        return userList;
    }
}

二、分层解耦

2.1 三层架构

Spring Boot 应用通常遵循经典的"三层架构"。分层的核心目的是单一职责原则****(Single Responsibility Principle),即每一层只专注于处理特定类型的任务。

  • controller控制层,接收前端发送的请求,对请求进行处理,并响应数据。
  • service业务逻辑层,处理具体的业务逻辑。
  • dao数据访问层,负责数据访问操作,包括数据的增删改查。


案例:对第一章节的SpringBoot项目进行拆分

Dao层

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

Service层

java 复制代码
public class UserServiceImpl implements UserService {

    private UserDao userDao = new UserDaoImpl();
    @Override
    public List<User> findAll() {
        List<String> lines = userDao.findAll();
        List<User> userList = lines.stream().map(line -> {
            String[] split = line.split(",");
            return new User(
                    Integer.parseInt(split[0]),
                    split[1],
                    split[2],
                    split[3],
                    Integer.parseInt(split[4]),
                    LocalDateTime.parse(split[5], DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        }).toList();
        return userList;
    }
}

Controller层

java 复制代码
@RestController //@Controller + @ResponseBody -----> 如果返回的是一个对象/集合 --> 转json --> 响应
public class UserController {

    private UserService userService = new UserServiceImpl();

    @RequestMapping("/list")
    public List<User> list() {
        List<User> userList = userService.findAll();
        return userList;
    }
}

2.2 分层解耦

  • 耦合:衡量软件中各个层/各个模块的依赖关联程度。
  • 内聚:软件中各个功能模块内部的功能联系。
  • 软件设计原则:高内聚,低耦合。

我们在实现UserController来接收Service层传过来处理好的数据时,需要自己在UserController中手动创建一个UserServiceImpl的对象,才能调用业务处理的实现。两个层之间存在着联系,我们就称项目耦合。

2.3 IOC&DI

看了上述例子之后,我们可以清楚的感知到目前虽然实现了三层架构,但是项目仍然存在耦合现象,那么如何解决上述现象呢,Spring框架给我们提供了解决方案:

即使使用了接口,最终系统中总需要有一个地方来实例化具体的对象。Spring Boot 通过其核心的 Spring 容器(IoCContainer) 彻底接管了这一过程。这一方法叫做控制反转。

将容器中的对象分配给另一个层的对象时,Spring 容器会在运行时自动将目标对象分配(注入)给它。这一过程叫做DI(依赖注入)

Bean对象:IOC容器中创建、管理的对象,称之为Bean。

案例:将我们上述分成三层架构的SpringBoot项目进行低耦合的调整。

  1. 将Dao和Service层的实现类交给IOC容器管理
  2. 为Controller和Service注入运行时所依赖的对象

1.将Dao和Service层的实现类,交给IOC容器管理。只需要在Dao、Service的实现类顶部添加一个**@Component**注解。

2.为Controller和Service注入运行时所依赖的对象。在Controller和Service创建对象的语句上方添加**@AutoWired**注解,就会在容器中自动查找所需的对象。

2.3.1 IOC详解

要把某个对象交给IOC容器管理,需要在对应的类上加上如下注解之一:

注意:声明bean的时候,可以通过注解的value属性指定bean的名字,如果没有指定,默认为类名首字母小写。

  • 前面声明bean的四大注解,要想生效,还需要被组件扫描注解@ComponentScan扫描。
  • 该注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解 @SpringBootApplication中,默认扫描的范围是启动类所在包及其子包

所在包及其子包:

2.3.2 DI详解

基于@AutoWired进行依赖注入的常见方式有如下三种:

属性注入:

构造函数注入:

setter注入:


@AutoWired注解,默认是按照类型注入的。

如果存在多个相同类型的Bean,将会报错

解决方案:

相关推荐
EM-FF4 小时前
idea快捷键
java·ide·intellij-idea
薪火铺子5 小时前
Redis 分布式锁与 Redisson 原理深度解析
java·redis·分布式·后端
胡楚昊5 小时前
BUU WEB之旅(1)
java·数据库·mybatis
牢七5 小时前
链条合集整理
java·开发语言
小雅痞5 小时前
[Java][Leetcode hard] 30. 串联所有单词的子串
java·leetcode
钝挫力PROGRAMER5 小时前
static final 指向可变集合的设计模式
java·设计模式
青山师6 小时前
Java反射深度解析:运行时探查的艺术、代价与工程实践
java·开发语言·面试·反射·java程序员·java核心
安当加密6 小时前
Spring Boot应用接入国产安当凭据管理系统SMS Starter实战(附源码)
java·spring boot·后端
skilllite作者6 小时前
Deer-Flow 工作流引擎深度评测报告
java·大数据·开发语言·chrome·分布式·架构·rust