概述
在软件开发中,"高内聚、低耦合"是构建可维护、可扩展系统的重要设计原则。Spring 框架通过其核心机制——IOC(控制反转)和 AOP(面向切面编程),为我们提供了一套完善的解耦解决方案。本文将深入探讨 Spring 如何实现组件间的解耦,以及如何在实际项目中应用这些技术。
IOC/DI:控制反转与依赖注入
概念解析
IOC (Inversion of Control - 控制反转) 是一种设计思想,它将传统程序中由程序员控制的对象创建和生命周期管理权"反转"给 Spring 容器。这种转变带来了巨大的灵活性,使程序组件不再紧密耦合。
DI (Dependency Injection - 依赖注入) 是 IOC 的具体实现方式,容器动态地将对象所依赖的其他组件注入到目标对象中,通常通过 Setter 方法或构造器实现。
传统方式 vs Spring IOC 方式
```java
// 传统方式 - 紧耦合
public class UserService {
private UserRepository userRepository = new UserRepositoryImpl();
}
// Spring IOC 方式 - 解耦
public class UserService {
private UserRepository userRepository;
// 通过构造器注入
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
// 或通过setter注入
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
```
Bean 的单例模式
Spring 容器中的 Bean 默认采用单例模式,容器内部使用类似 `ConcurrentHashMap` 的结构存储和管理这些实例。需要注意的是,这种单例是"每个 Spring 容器内"的单例,而非 JVM 级别的单例。
Bean 的创建时机
Spring 提供了两种容器,对应不同的 Bean 创建策略:
1. ApplicationContext:饿汉式加载,在初始化配置文件时立即创建所有单例 Bean
2. BeanFactory:懒汉式加载,只有在第一次请求时才创建 Bean 实例
Bean 的实例化方式
Spring 支持多种 Bean 实例化方式:
```xml
<!-- 1. 构造器实例化(最常用) -->
<bean id="dept" class="com.example.pojo.Dept"/>
<!-- 2. 普通工厂模式 -->
<bean id="factory" class="com.example.util.DeptFactory"/>
<bean id="dept4" factory-bean="factory" factory-method="getObj"/>
<!-- 3. 静态工厂模式 -->
<bean id="dept4" class="com.example.util.DeptFactory" factory-method="getObj"/>
```
属性注入的三种方式
```xml
<!-- 1. 构造器注入 -->
<bean id="dept3" class="com.example.pojo.Dept">
<constructor-arg index="0" value="10"/>
<constructor-arg name="dname" value="运维组"/>
<constructor-arg index="2" value="北京"/>
</bean>
<!-- 2. setter方法注入 -->
<bean id="dept5" class="com.example.pojo.Dept">
<property name="deptno" value="99"/>
<property name="dname" value="设计部门"/>
<property name="loc" value="上海"/>
</bean>
<!-- 3. 自动注入 -->
<bean id="ddi" class="com.example.dao.Impl.DeptDaoImpl" autowire="byName"/>
```
AOP:面向切面编程
AOP 通过横向抽取公共功能(如日志、事务、安全等),进一步实现业务逻辑与非业务逻辑的解耦。
AOP 实现方式
1. 静态代理:编译期确定代理对象,代理类数量会增多
2. 动态代理:
- JDK 动态代理:基于接口实现
- CGLIB 动态代理:基于父类实现
3. Spring AOP:默认使用 JDK 动态代理,可通过配置切换为 CGLIB
AOP 实战示例
```java
// 定义切面
@Aspect
@Component
public class LoggingAspect {
@Before("execution( com.example.service..(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("方法执行前: " + joinPoint.getSignature().getName());
}
@AfterReturning(pointcut = "execution( com.example.service..(..))",
returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
System.out.println("方法返回后: " + result);
}
}
```
事务管理:传播策略的应用
在业务层中,一个方法可能需要调用多个 mapper 方法,这些操作应该在一个事务中执行。Spring 的事务传播策略解决了这个问题。
事务传播策略配置
```xml
<!-- Spring接管mybatis-session对象所管理的事务 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 启用注解驱动的事务管理 -->
<tx:annotation-driven transaction-manager="txManager"/>
```
使用 REQUIRED 传播策略
```java
@Service
@Transactional(propagation = Propagation.REQUIRED)
public class EmpServiceImpl implements EmpService {
@Autowired
private EmpMapper empMapper;
@Override
public int alterEmp(Emp emp) {
int i = 0;
i = empMapper.deleteEmpByEmpno(7782);
i += empMapper.updateByEmpno(emp);
return i;
}
}
```
测试事务
```java
@Test
public void testTransaction() {
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
EmpService es = app.getBean("empServiceImpl", EmpService.class);
Emp emp = new Emp();
emp.setSal(0.0);
emp.setEmpno(7876);
try {
int i = es.alterEmp(emp);
System.out.println("事务提交成功");
} catch (Exception e) {
System.out.println("事务回滚");
}
}
```
总结
Spring 框架通过 IOC/DI 和 AOP 两大核心技术,为软件解耦提供了完善的解决方案:
| 概念 | 核心思想 | 实现方式/目的 |
|------|---------|--------------|
| IOC/DI | 控制反转,将对象创建和组装的权力交给容器 | 解耦,通过 XML 或注解配置依赖关系 |
| AOP | 面向切面编程,横向抽取公共功能 | 解耦非业务逻辑(日志、事务等),使用动态代理技术实现 |
| 事务传播 | 管理多个数据库操作的事务边界 | 使用 REQUIRED 等传播行为确保业务方法内多个操作原子性 |
通过合理运用这些技术,我们可以构建出更加灵活、可维护和可扩展的应用程序,真正实现"高内聚、低耦合"的设计目标。
最佳实践建议
1. 优先使用注解配置:`@Autowired`, `@Component`, `@Service` 等注解使配置更简洁
2. 合理选择注入方式:构造器注入适合强制依赖,setter 注入适合可选依赖
3. 谨慎使用自动注入:明确指定注入的 Bean 名称,避免意外行为
4. 合理使用 AOP:识别横切关注点,避免过度使用导致系统难以理解
5. 事务边界规划:根据业务需求选择合适的事务传播行为
Spring 的解耦机制不仅是一种技术,更是一种设计哲学,它指导我们构建更加优雅和可持续的软件系统。
1011

被折叠的 条评论
为什么被折叠?



