一、Spring 概述
1.1 Spring 介绍
Spring 是轻量级 Java EE 应用开源框架(全栈式开发框架,官网: http://spring.io ),由 Rod Johnson 创建,旨在解决企业级编程开发的复杂性。
1.2 Spring 的优点
- IOC:解决传统 Web 开发中硬编码所造成的程序耦合(控制反转)
- AOP:在运行期间不修改源代码对程序进行增强(切面编程)
- 粘合剂:除自身功能外,还提供整合其他技术和框架的能力
1.3 Spring 的体系结构

Spring 框架按功能分为五大模块:
| 模块分类 | 核心功能 |
|---|---|
| Core Container(核心容器) | 提供 IOC 和依赖注入特性,是框架最基础部分 |
AOP、Aspects、Instrumentation(检测)、Messaging(消息处理) |
提供面向切面编程实现、检测、消息处理等 |
Data Access/Integration(数据访问与集成) |
简化持久层操作 |
| Web | 提供 Spring MVC 框架及与 Servlet、WebSocket 的集成 |
| Test | 方便程序测试 |
1.4 Spring 的发展历程
- 1997 年 IBM 提出了 EJB 的思想
- 1998 年,SUN 制定开发标准规范 EJB1.0
- 1999 年,EJB1.1 发布
- 2001 年,EJB2.0 发布
- 2003 年,EJB2.1 发布Rod Johnson (spring 之父)
Expert One-to-One J2EE Design and Development(2002):阐述了 J2EE 使用 EJB 开发设计的优点及解决方案Expert One-to-One J2EE Development without EJB(2004):阐述了 J2EE 开发不使用 EJB 的解决方式(Spring 雏形)
- 2006 年,EJB3.0 发布
- 2017 年 9 月发布了 Spring 的最新版本 Spring5.0 通用版
- ......
二、Spring IOC(重点)
2.1 程序的耦合
-
耦合:对象之间的依赖关系,耦合越高,维护成本越高
-
传统开发耦合案例:没有引入 IOC 容器时系统的 Web 层、业务层、持久层存在耦合
/**
-
持久层实现类
*/
public class UserDaoImpl implements UserDao {@Override
public void addUser(){
System.out.println("insert into tb_user......");
}
}
/**
-
业务层实现类
*/
public class UserServiceImpl implements UserService {
//硬编码:此处有依赖关系
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();
}
}
-
-
问题分析:service 层依赖 dao 层实现类,若修改 dao 实现类或缺失 dao 实现类,编译失败
-
IOC (工厂模式) 解耦 步骤 :
- 把所有的 dao 和 service 对象使用配置文件配置起来
- 当服务器启动时读取配置文件
- 把这些对象通过反射创建 出来并保存在容器(Map)中
- 在使用的时候,直接从工厂拿
2.2 工厂模式的 IOC 解决程序耦合
2.2.1 什么是 IOC
-
IOC (Inverse of Control) 即控制反转:正转是自己创建依赖对象;反转是由IOC 工厂来创建依赖对象;
-
传统方式:主动 new 创建依赖对象。

-
IOC 方式:被动从 IOC 工厂获取依赖对象。

这种被动接收的方式获取对象的思想就是控制反转,它是 spring 框架的核心之一。
2.2.2 工厂模式的 IOC 解耦
-
案例一:
/**
-
bean工厂
*/
public class BeanFactory_v1 {/**
- 获得UserServiceImpl对象
- @return
*/
public static UserService getUserService(){
return new UserServiceImpl();
}
/**
- 获得UserDaoImpl对象
- @return
*/
public static UserDao getUserDao(){
return new UserDaoImpl();
}
}
-
问题:我们在开发中会有很多个 service 和 dao,此时工厂类就要添加无数个方法。
- 案例二:
配置文件(bean.properties):
properties
#1、配置要使用的dao和service
UserDao=com.hg.dao.UserDaoImpl
UserService=com.hg.service.UserServiceImpl
工厂类:
/**
* bean工厂
*/
public class BeanFactory_v2 {
private static Properties prop = new Properties();
/**
* 根据全类名获取bean对象
* @param beanName
* @return
* @throws ClassNotFoundException
*/
public static Object getBean(String beanName) {
try {
//不能使用:web工程发布后没有src目录
//InputStream is = new FileInputStream("src/bean.properties");
InputStream is =
BeanFactory_v2.class.getClassLoader()
.getResourceAsStream("bean.properties");
prop.load(is);
return Class.forName(prop.getProperty(beanName)).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
System.out.println(prop.get("UserService"));
System.out.println(getBean("UserService"));
}
}
业务层实现类:
/**
* 业务层实现类
*/
public class UserServiceImpl implements UserService {
private UserDao userDao = (UserDao) BeanFactory.getBean("UserDao");
public void addUser(){
userDao.addUser();
}
}
测试类:
运行
/**
* 模拟表现层
*/
public class Client {
public static void main(String[] args) {
//直接引用接口实现类
for (int i = 0; i < 5; i++) {
UserService userService =
(UserService)BeanFactory_v2.getBean("UserService");
System.out.println(userService);
}
}
}

问题:
- 每次都会创建新的对象
- 程序运行时才创建对象 (读取配置文件)
-
案例三:
package com.hg.factory;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;/**
-
bean工厂
*/
public class BeanFactory_v3 {//定义一个容器,用于存放对象
private static Map<String, Object> beans = new HashMap<>();/**
-
加载配置文件
*/
static {
try {
//2、读取配置文件
//不能使用:web工程发布后没有src目录
//InputStream is = new FileInputStream("src/bean.properties");
InputStream is =
BeanFactory_v3.class.getClassLoader()
.getResourceAsStream("bean.properties");//3、通过反射创建对象,把对象存到容器中 Properties prop = new Properties(); prop.load(is); Set<Map.Entry<Object, Object>> entrySet = prop.entrySet(); for (Map.Entry<Object, Object> entry : entrySet) { String key = entry.getKey().toString(); String beanName = entry.getValue().toString(); Object value = Class.forName(beanName).newInstance(); beans.put(key, value); }} catch (Exception e) {
e.printStackTrace();
}
}
/**
- 4、在使用的时候,直接从工厂拿
- @param beanName
- @return
*/
public static Object getBean(String beanName) {
try {
return beans.get(beanName);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
System.out.println(getBean("UserService"));
}
} -
-
2.3 Spring 的 IOC 解决程序耦合
2.3.1 创建工程

2.3.1.1 pom.xml
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.hg</groupId>
<artifactId>Spring_IOC_Xml</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<!-- 项目源码及编译输出的编码 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- 项目编译JDK版本 -->
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- Spring常用依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
</dependencies>
</project>
注意:Jar 包彼此存在依赖,只需引入最外层 Jar 即可由 Maven 自动将相关依赖 Jar 引入到项目中。
| Spring 常用功能的 Jar 包依赖关系 |
|---|
![]() |
核心容器模块说明:
- spring-beans + spring-core:提供 IOC/DI,BeanFactory(延迟加载)
- spring-context:扩展 BeanFactory,ApplicationContext(立即加载)
- spring-expression:Spring 表达式语言
2.3.1.2 dao
/**
* 持久层实现类
*/
public class UserDaoImpl implements UserDao {
@Override
public void addUser(){
System.out.println("insert into tb_user......");
}
}
2.3.1.3 service
/**
* 业务层实现类
*/
public class UserServiceImpl implements UserService {
//此处有依赖关系
private UserDao userDao = new UserDaoImpl();
@Override
public void addUser(){
userDao.addUser();
}
}
2.3.2 IOC
2.3.2.1 applicationContext.xml
xml
XML
<?xml version="1.0" encoding="UTF-8"?>
<!--1、注意:要导入schema约束-->
<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">
<!--
2、<bean>标签作用:通过反射创建对象并交给spring的ioc容器去管理
id:给对象在容器中提供一个唯一标识。用于获取对象
class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数
-->
<bean id="userDao" class="com.hg.dao.UserDaoImpl"></bean>
<bean id="userService" class="com.hg.service.UserServiceImpl"></bean>
</beans>
注意:命名无限制,约定俗成命名有:spring-context.xml、applicationContext.xml、beans.xml
2.3.2.2 测试
运行
/**
* 模拟表现层
*/
public class Client {
public static void main(String[] args) {
//1.使用ApplicationContext接口,就是在获取spring容器
ApplicationContext ac = new
ClassPathXmlApplicationContext("applicationContext.xml");
//2.根据bean的id获取对象
UserDao userDao = (UserDao) ac.getBean("userDao");
System.out.println(userDao);
UserService userService = (UserService) ac.getBean("userService");
System.out.println(userService);
userService.addUser();
}
}
- 问题:service 层仍然耦合
2.3.3 DI
概述:DI(Dependency Injection)依赖注入:将依赖对象(userDao)从容器中拿出来赋值给调用者(userService)
2.3.3.1 构造函数注入
使用类中的构造函数,给成员变量赋值。注意,赋值的操作不是我们自己做的,而是通过配置的方式,让 spring 框架来为我们注入。具体代码如下:
/**
* 业务层实现类
*/
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;
}
public void addUser(){
System.out.println(name+","+age);
userDao.addUser();
}
}
xml
XML
<?xml version="1.0" encoding="UTF-8"?>
<!--1、注意:要导入schema约束-->
<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">
<!--2、把对象交给spring来创建-->
<bean id="userDao" class="com.hg.dao.UserDaoImpl"></bean>
<bean id="userService" class="com.hg.service.UserServiceImpl">
<!--
要求:类中需要提供一个对应参数列表的构造函数。
标签:constructor-arg
==给谁赋值:==
index:指定参数在构造函数参数列表的索引位置
name:指定参数在构造函数中的名称
==赋什么值:==
value:它能赋的值是基本数据类型和String类型
ref:它能赋的值是其他bean类型,也就是说,必须得是在配置文件中配置过的bean
-->
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
<constructor-arg name="name" value="张三"></constructor-arg>
<constructor-arg index="2" value="18"></constructor-arg>
</bean>
</beans>
2.3.3.2 set 方法注入
顾名思义,就是在类中提供需要注入成员的 set 方法。具体代码如下:
/**
* 业务层实现类
*/
public class UserServiceImpl implements UserService {
private UserDao userDao;
private String name;
private Integer age;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void addUser(){
System.out.println(name+","+age);
userDao.addUser();
}
}
xml
<?xml version="1.0" encoding="UTF-8"?>
<!--1、注意:要导入schema约束-->
<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">
<!--2、把对象交给spring来创建-->
<bean id="userDao" class="com.hg.dao.UserDaoImpl"></bean>
<bean id="userService" class="com.hg.service.UserServiceImpl">
<!--
要求:必须提供set方法
标签:property
==给谁赋值:==
name:找的是类中set方法后面的部分
==赋什么值:==
value:它能赋的值是基本数据类型和String类型
ref:它能赋的值是其他bean类型,也就是说,必须得是在配置文件中配置过的bean
-->
<property name="userDao" ref="userDao"></property>
<property name="name" value="张三"></property>
<property name="age" value="18"></property>
</bean>
</beans>
2.3.3.3 自动注入
不用在配置中 指定为哪个属性赋值,由 spring 自动根据某个 "原则" ,在工厂中查找一个 bean 并为属性注入值。具体代码如下:
/**
* 业务层实现类
*/
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void addUser(){
userDao.addUser();
}
}
xml
<?xml version="1.0" encoding="UTF-8"?>
<!--1、注意:要导入schema约束-->
<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">
<!--2、把对象交给spring来创建-->
<bean id="userDao" class="com.hg.dao.UserDaoImpl"></bean>
<!--autowire="byType":按照类型自动注入值-->
<bean id="userService" class="com.hg.service.UserServiceImpl" autowire="byType">
</bean>
</beans>
