一、Spring框架简介
Spring是一个轻量级的、开源的JavaEE全栈式应用框架。它的核心价值在于简化企业级应用开发,通过提供一系列模块化解决方案,让开发者能够更专注于业务逻辑。
Spring的核心优势:
-
IOC(控制反转):将对象的创建、管理与依赖关系的控制权从程序代码"反转"到Spring容器,实现解耦。
-
AOP(面向切面编程):允许将遍布应用的公共行为(如日志、事务)从核心业务逻辑中分离,增强模块化。
-
粘合剂:它就像一个"框架的框架",能够非常方便地整合MyBatis、Hibernate、Struts等其他优秀的第三方技术与框架。
二、IOC(控制反转):从工厂模式到Spring容器
2.1 问题起源:耦合
在传统编码中,对象间的依赖关系通常是"硬编码"的。例如,在Service层中直接new一个Dao层的实现类。这种强耦合导致代码僵化,一旦需要更换实现,就必须修改源代码。
2.2 IOC思想
-
正转 :程序员在代码中主动
new对象,控制权在程序员手中。 -
反转(IOC):对象的创建不再由程序员控制,而是交给一个"工厂"或"容器"来负责。程序员从主动创建变为被动接收对象。
核心 :控制对象的创建权发生反转。
2.3 手工实现IOC:工厂模式
在接触Spring前,我们可以用"工厂+反射+配置文件"模拟IOC思想,解耦Service和Dao。
实现步骤:
-
定义配置文件 (
bean.properties):将类名以键值对形式存储。userDao=com.hg.dao.UserDaoImpl userService=com.hg.service.UserServiceImpl -
创建工厂类:在静态代码块中读取配置文件。
-
反射创建对象 :通过
Class.forName(className).newInstance()创建对象实例,并存入一个Map容器。 -
提供获取方法 :对外提供
getBean(String id)方法,从Map中返回所需对象。
此时,Service中不再出现new UserDaoImpl()的代码,而是从工厂获取,初步实现解耦。
2.4 Spring的IOC容器
Spring将上述工厂模式的思想发挥到极致,提供了一个功能强大的IOC容器。
Spring IOC 入门步骤:
-
引入依赖 (
pom.xml)<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.23</version> <!-- 请使用合适版本 --> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.36</version> </dependency> -
准备日志配置 (
log4j.properties) -
编写Spring配置文件 (
applicationContext.xml)<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- bean标签:将一个类的对象交给Spring IOC容器管理 --> <!-- id: 对象在容器中的唯一标识 (Map的key) --> <!-- class: 对象的全限定类名 --> <bean id="userDao" class="com.hg.dao.UserDaoImpl"></bean> <bean id="userService" class="com.hg.service.UserServiceImpl"></bean> </beans> -
从容器中获取Bean
public class Test { public static void main(String[] args) { // 1. 加载Spring配置文件,初始化IOC容器 ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); // 2. 从容器中获取Bean对象 UserService userService = ac.getBean("userService", UserService.class); // 3. 使用对象 userService.saveUser(); } }
三、DI(依赖注入)
IOC解决了对象创建的问题。**DI(依赖注入)** 则专门解决对象间的依赖关系赋值问题,它是IOC思想的具体实现。
3.1 构造方法注入
通过类的构造方法来完成依赖的注入。
-
目标类提供带参构造方法
public class UserServiceImpl implements UserService { private UserDao userDao; private String msg; // 构造方法 public UserServiceImpl(UserDao userDao, String msg) { this.userDao = userDao; this.msg = msg; } } -
在配置文件中使用
<constructor-arg>标签注入<bean id="userService" class="com.hg.service.UserServiceImpl"> <!-- name: 通过构造方法参数名匹配 --> <constructor-arg name="userDao" ref="userDao"/> <!-- index: 通过构造方法参数索引位置匹配 (从0开始) --> <constructor-arg index="1" value="示例文本"/> </bean> <bean id="userDao" class="com.hg.dao.UserDaoImpl"/>-
ref:引用IOC容器中其他Bean的id。 -
value:注入基本数据类型或String类型的值。
-
3.2 Setter方法注入(最常用)
通过类的Setter方法来完成依赖注入。
-
目标类提供Setter方法
public class UserServiceImpl implements UserService { private UserDao userDao; private String msg; // Setter 方法 public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void setMsg(String msg) { this.msg = msg; } } -
在配置文件中使用
<property>标签注入<bean id="userService" class="com.hg.service.UserServiceImpl"> <!-- name: 取set方法名去掉"set"后首字母小写的部分,例如setUserDao -> userDao --> <property name="userDao" ref="userDao"/> <property name="msg" value="示例文本"/> </bean> <bean id="userDao" class="com.hg.dao.UserDaoImpl"/>
3.3 自动注入(Autowire)
让Spring容器自动寻找匹配的Bean并完成注入,无需在<property>或<constructor-arg>中显式配置。
byType方式 :根据属性的类型 ,在IOC容器中查找匹配的Bean。要求容器中同类型的Bean必须唯一。
<bean id="userService" class="com.hg.service.UserServiceImpl" autowire="byType"/>
<bean id="userDao" class="com.hg.dao.UserDaoImpl"/>
<!-- 注意:不能再有另一个类型为UserDao的bean,否则会报错 -->
原理 :Spring会遍历IOC容器中所有的Bean,检查其类型是否与UserServiceImpl中需要注入的属性(如UserDao)类型匹配,如果找到且唯一,则自动注入。
总结
-
IOC 是一种设计思想,将对象的控制权交给容器,实现解耦。
-
DI 是IOC的一种实现方式,由容器在运行时动态地将依赖关系注入到组件中。
-
**在Spring中,IOC容器通过读取配置(XML或注解)来管理Bean及其依赖关系,DI则负责建立Bean之间的关联。** 从手写工厂到使用Spring容器,我们看到了这一思想从概念到强大工业级实现的演进过程。