文章目录
标签: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;