前言
Spring 框架作为 Java EE 开发的中流砥柱,其核心思想(IOC 控制反转、AOP 面向切面编程)彻底解决了传统开发中代码耦合、功能复用性差等问题。本文将从 Spring 概述入手,逐步拆解 IOC 和 AOP 的实现原理、配置方式,结合实战案例让你彻底掌握 Spring 核心!
一、Spring 概述
1.1 Spring 是什么?
Spring 是轻量级 Java EE 应用开源框架(官网:http://spring.io/),由 Rod Johnson 为解决企业级编程开发的复杂性而创建。它并非替代现有框架,而是通过整合各类技术,为开发者提供一站式解决方案。
1.2 Spring 简化开发的核心体现
| 特性 | 作用 |
|---|---|
| IOC(控制反转) | 解决传统开发中硬编码导致的程序耦合问题 |
| AOP(面向切面编程) | 运行期间不修改源代码即可对程序功能增强 |
| 粘合剂特性 | 提供整合 MyBatis、Struts2 等其他框架的能力 |
1.3 Spring 体系结构
Spring 框架按功能划分为五大核心模块:
- Core Container(核心容器):提供 IOC 和 DI(依赖注入)核心能力,包含 beans、core、context、expression 模块。
- AOP + Aspects:面向切面编程实现,支持功能增强。
- Data Access/Integration:简化持久层操作,整合 JDBC、ORM(MyBatis/Hibernate)等。
- Web:提供 Spring MVC 框架,支持 Servlet、WebSocket 等 Web 开发。
- Test:集成 JUnit、TestNG 等测试框架,简化单元测试。
1.4 Spring 发展历程
- 1997 年:IBM 提出 EJB 思想;
- 2002 年:Rod Johnson 发布《Expert One-to-One J2EE Design and Development》,阐述 EJB 开发痛点;
- 2004 年:《Expert One-to-One J2EE Development without EJB》发布,奠定 Spring 雏形;
- 2017 年:Spring 5.0 通用版发布,至今仍是主流版本。
二、Spring IOC(控制反转)- 核心重点
2.1 程序耦合的问题
传统开发中,Web 层、业务层、持久层存在强耦合,例如:
java
// 持久层实现类
public class UserDaoImpl implements UserDao {
@Override
public void addUser(){
System.out.println("insert into tb_user......");
}
}
// 业务层实现类
public class UserServiceImpl implements UserService {
// 硬编码依赖:直接new Dao层对象
private UserDao userDao = new UserDaoImpl();
public void addUser(){
userDao.addUser();
}
}
// 表现层
public class Client {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
userService.addUser();
}
}
问题分析:若修改 Dao 层实现类,Service 层编译失败,耦合度极高。
2.2 IOC 核心思想:控制反转
- 正传:开发者主动 new 对象(如上述代码),控制对象创建权;
- 反转:由 IOC 工厂统一创建、管理对象,开发者被动获取,实现解耦。
2.2.1 工厂模式实现 IOC 解耦(手动实现)
步骤 1:编写配置文件(bean.properties)
java
UserDao=com.hg.dao.UserDaoImpl
UserService=com.hg.service.UserServiceImpl
步骤 2:实现 IOC 工厂类
java
public class BeanFactory {
// 容器存储对象
private static Map<String, Object> beans = new HashMap<>();
// 静态代码块加载配置文件并创建对象
static {
try {
InputStream is = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
Properties prop = new Properties();
prop.load(is);
// 遍历配置文件,反射创建对象
Set<Object> keys = prop.keySet();
for (Object key : keys) {
String beanName = (String) key;
String className = prop.getProperty(beanName);
Object bean = Class.forName(className).newInstance();
beans.put(beanName, bean);
}
} catch (Exception e) {
throw new ExceptionInInitializerError("初始化Bean工厂失败");
}
}
// 获取对象方法
public static Object getBean(String beanName) {
return beans.get(beanName);
}
}
步骤 3:改造 Service 层
java
public class UserServiceImpl implements UserService {
// 从工厂获取对象,而非手动new
private UserDao userDao = (UserDao) BeanFactory.getBean("UserDao");
public void addUser(){
userDao.addUser();
}
}
2.3 Spring 官方 IOC 实现
2.3.1 快速上手(XML 配置)
步骤 1:创建 Maven 工程,引入依赖
XML
<dependencies>
<!-- Spring核心依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
</dependencies>
步骤 2:编写 Spring 配置文件(applicationContext.xml)
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">
<!-- 将对象交给Spring容器管理 -->
<bean id="userDao" class="com.hg.dao.UserDaoImpl"></bean>
<bean id="userService" class="com.hg.service.UserServiceImpl"></bean>
</beans>
步骤 3:测试获取容器对象
java
public class Client {
public static void main(String[] args) {
// 加载配置文件,创建Spring容器
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
// 从容器获取对象
UserDao userDao = (UserDao) ac.getBean("userDao");
UserService userService = (UserService) ac.getBean("userService");
userService.addUser();
}
}
2.3.2 DI(依赖注入)- 解决 Service 层耦合
IOC 解决对象创建问题,DI 解决对象依赖赋值问题,核心有 4 种注入方式:
方式 1:构造函数注入
java
// Service层
public class UserServiceImpl implements UserService {
private UserDao userDao;
private String name;
private Integer age;
// 构造方法
public UserServiceImpl(UserDao userDao, String name, Integer age) {
this.userDao = userDao;
this.name = name;
this.age = age;
}
@Override
public void addUser(){
System.out.println(name + "," + age);
userDao.addUser();
}
}
XML
<!-- 配置文件 -->
<bean id="userDao" class="com.hg.dao.UserDaoImpl"></bean>
<bean id="userService" class="com.hg.service.UserServiceImpl">
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
<constructor-arg name="name" value="张三"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
</bean>
方式 2:Set 方法注入(最常用)
java
// Service层
public class UserServiceImpl implements UserService {
private UserDao userDao;
private String name;
private Integer age;
// Set方法
public void setUserDao(UserDao userDao) {this.userDao = userDao;}
public void setName(String name) {this.name = name;}
public void setAge(Integer age) {this.age = age;}
@Override
public void addUser(){
System.out.println(name + "," + age);
userDao.addUser();
}
}
XML
<!-- 配置文件 -->
<bean id="userDao" class="com.hg.dao.UserDaoImpl"></bean>
<bean id="userService" class="com.hg.service.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
<property name="name" value="张三"></property>
<property name="age" value="18"></property>
</bean>
方式 3:自动注入
XML
<!-- byType:按类型注入;byName:按bean的id注入 -->
<bean id="userDao" class="com.hg.dao.UserDaoImpl"></bean>
<bean id="userService" class="com.hg.service.UserServiceImpl" autowire="byType"></bean>
方式 4:集合类型注入(了解)
java
// Service层
public class UserServiceImpl implements UserService {
private String[] myStrs;
private List<String> myList;
private Set<String> mySet;
private Map<String,String> myMap;
// Set方法省略...
@Override
public void addUser(){
System.out.println(Arrays.toString(myStrs));
System.out.println(myList);
System.out.println(mySet);
System.out.println(myMap);
}
}
XML
<!-- 配置文件 -->
<bean id="userService" class="com.hg.service.UserServiceImpl">
<property name="myStrs">
<array>
<value>AAA</value>
<value>BBB</value>
</array>
</property>
<property name="myList">
<list>
<value>AAA</value>
<value>BBB</value>
</list>
</property>
<property name="mySet">
<set>
<value>AAA</value>
<value>BBB</value>
</set>
</property>
<property name="myMap">
<map>
<entry key="key1" value="value1"></entry>
<entry key="key2" value="value2"></entry>
</map>
</property>
</bean>
未完待续~~~