6 初识Spring框架
约 7123 字大约 24 分钟
2025-12-22
学习目标
- 了解Spring框架及其优点
- 了解Spring框架的体系结构与Spring5的新特性
- 熟悉Spring框架的下载及目录结构
- 掌握Spring框架入门程序的编写
- 理解控制反转的概念
- 掌握依赖注入的概念、类型和应用
Spring致力于解决Java EE应用中的各种问题,对于Java开发者来说,熟练使用Spring框架是必备技能之一。Spring具有良好的设计和分层结构,它克服了传统重量级框架臃肿、低效的劣势,极大简化了项目开发中的技术复杂性。
6.1 Spring介绍
6.1.1 Spring概述
早期Java EE的规范较为复杂,尤其是Java EE平台中的EJB(Enterprise Java Beans,企业级JavaBeans)标准在设计中存在缺陷,导致开发过程中的使用非常复杂,代码侵入性强,应用程序的测试和部署也较为困难,所以Spring于2003年应运而生。
Spring是由Rod Johnson组织和开发的一个分层的Java SE/Java EE一站式(full-stack)轻量级开源框架。它最为核心的理念是控制反转(Inversion of Control,IoC)和面向切面编程(Aspect Oriented Programming,AOP)。其中,IoC是Spring的基础,它支撑着Spring对Java Bean的管理功能;AOP是Spring的重要特性,通过预编译方式和运行期间动态代理实现程序功能,能够在不修改源代码的情况下,为程序统一添加功能。
Spring贯穿于表现层、业务逻辑层和持久层,Spring在每个层的作用如下:
- 在表现层提供了Spring MVC框架。
- 在业务逻辑层可以管理事务、记录日志等。
- 在持久层可以整合MyBatis、Hibernate、JdbcTemplate等技术。
虽然Spring贯穿于表现层、业务逻辑层和持久层,但Spring开发者并不想让Spring取代那些已有的框架,而是以高度的开放性与它们进行无缝整合。
6.1.2 Spring框架的优点
Spring作为Java EE的一个全方位应用程序框架,为开发企业级应用提供了健壮、高效的解决方案。它不仅可以应用于Java应用的开发,也可以应用于服务器端开发。Spring之所以得到如此广泛应用,是因为Spring框架具有以下几个优点:
- 非侵入式设计Spring是一种非侵入式(non-invasive)框架,所谓非侵入式是指允许应用程序自由选择和组装Spring框架的各个功能模块,并且不要求应用程序的类必须继承或者实现Spring框架的某个类或接口。由于业务逻辑中没有Spring的API,所以业务逻辑代码也可以从Spring框架快速地移植到其他框架。
- 降低耦合性,方便开发Spring就是一个"大工厂",可以将所有对象的创建和依赖关系的维护工作都交给Spring容器管理,从而极大降低了组件之间的耦合性。
- 支持AOP编程Spring提供了对AOP的支持,AOP可以将一些通用的任务进行集中处理,例如安全、事务和日志等,以减少通过传统面向对象编程(Object Oriented Programming,OOP)方法带来的代码冗余。
- 支持声明式事务在Spring中,可以直接通过Spring配置文件管理数据库事务,省去了手动编程的繁琐,提高了开发效率。
- 方便程序的测试Spring提供了对JUnit的支持,开发人员可以通过JUnit进行单元测试。
- 方便集成各种优秀框架Spring提供了一个广阔的基础平台,其内部提供了对各种框架的直接支持,如Struts、Hibernate、MyBatis、Quartz等,这些优秀框架可以与Spring无缝集成。
- 降低Java EE API的使用难度Spring对Java EE开发中的一些API(如JDBC、JavaMail等)进行了封装,大大降低了这些API的使用难度。
6.1.3 Spring的体系结构
Spring 是模块化的,允许使用者只选择适用于自己的模块。下面通过一张图展示 Spring的体系结构,具体如图6-1所示。

图6-1 Spring的体系结构
从图6-1可以看出,Spring 主要分为八大模块,其中,黑色背景的模块是Spring的主要模块,下面对这些模块进行简单介绍。
1. 核心容器(Core Container)
核心容器模块在Spring的功能体系中起着支撑作用,是其他模块的基石。核心容器层主要由Beans模块、Core模块、Context模块和SpEL模块组成,各个模块的介绍如下。
(1)Beans模块
Beans模块提供了BeanFactory类,是工厂模式的经典实现,Beans模块的主要作用是创建和管理Bean对象。
(2)Core模块
Core模块提供了Spring框架的基本组成部分,包括IoC和依赖注入(Dependence Injection,DI)功能。
(3)Context模块
Context模块构建于Beans模块和Core模块的基础上,它可以通过ApplicationContext接口提供上下文信息。
(4)SpEL模块
SpEL模块是Spring 3.0后新增的模块,提供了对SpEL(Spring Expression Language)的支持,SpEL是一个在程序运行时支持操作对象图的表达式语言。
2. 数据访问及集成(Data Access / Integration)
数据访问及集成模块用于访问和操作数据库中的数据,它主要包含JDBC模块、ORM模块、OXM模块、JMS模块和Transactions模块,下面分别进行介绍。
(1)JDBC模块
JDBC模块提供了一个JDBC的抽象层,JDBC模块消除了冗长的JDBC编码并能够解析数据库供应商特有的错误代码。
(2)ORM模块
ORM模块为主流的对象关系映射API提供了集成层,用于集成主流的对象关系映射框架,主流的对象关系映射框架包括 MyBatis、Hibernate和 JDO 等。
(3)OXM模块
OXM模块提供了对XML映射的抽象层的支持,如JAXB、Castor、XML Beans、JiBX和 XStream等。
(4)JMS模块
JMS模块主要用于传递消息,包含消息的生产和消费。自 Spring 4.1 版本后,JMS模块支持与Spring-message模块的集成。
(5)Transactions模块
Transactions模块的主要功能是事务管理,它支持Spring自动处理的声明式事务。
3. Web
Web模块的实现基于ApplicationContext,它提供了Web应用的各种工具类,包括了WebSocket模块、Servlet模块、Web MVC模块和Portlet模块,具体介绍如下。
(1)WebSocket模块
WebSocket模块是Spring 4.0以后新增的模块,它提供了WebSocket和SockJS的实现,以及对STOMP的支持。
(2)Servlet模块
Servlet模块提供了Spring的模型、视图、控制器,以及Web应用程序的REST Web服务实现。
(3)Web模块
Web模块提供了针对Web开发的集成特性,如大部分文件上传功能等。此外,Web模块还包含一个HTTP客户端和Spring远程处理支持的Web相关部分。
(4)Portlet模块
Portlet模块的功能类似于Servlet模块,提供了Portlet环境下的MVC实现。
4. 其他模块
Spring框架的其他模块还有 AOP模块、Aspects模块、Instrumentation模块、Messaging模块和Test模块,具体介绍如下。
(1)AOP模块
AOP模块提供了对面向切面编程的支持,程序可以定义方法拦截器和切入点,将代码按照功能进行分离,以降低程序的耦合性。
(2)Aspects模块
Aspects模块提供了与AspectJ集成的支持,AspectJ是一个功能强大且成熟的AOP框架,为面向切面编程提供了多种实现方法。
(3)Instrumentation模块
Instrumentation模块提供了对类工具的支持,并且实现了类加载器,该模块可以在特定的应用服务器中使用。
(4)Messaging模块
Messaging模块是Spring 4.0以后新增的模块,它提供了对消息传递体系结构和协议的支持。
(5)Test模块
Test模块提供了对程序单元测试和集成测试的支持。
6.1.4 Spring5的新特性
Spring5与旧版本相比,对Spring核心框架进行了修订和更新,增加了很多新特性,如支持响应式编程、支持函数式Web框架等。Spring5的新特性主要体现在以下几个方面。
1. 更新JDK基线
因为Spring5代码库运行于JDK8之上,所以Spring5对JDK的最低要求是JDK8,从而可以促进Spring的使用者积极运用Java8新特性。
2. 修订核心框架
Spring5利用JDK8的新特性对自身功能进行了修订,主要包括以下几个方面。
(1)基于JDK8的反射增强,通过Spring5提供的方法可以更加高效地对类或类的参数进行访问。
(2)核心的Spring接口提供了基于JDK8的默认方法构建的选择性声明。
(3)用@Nullable和@NotNull注解来表明可为空的参数及返回值,可以在编译时处理空值而不是在运行时抛出NullPointerException异常。
3. 更新核心容器
Spring5支持候选组件索引作为类路径扫描的替代方案。从索引读取实体类,会使加载组件索引开销更低,因此,Spring程序的启动时间将会缩减。
4. 支持响应式编程
响应式编程是另外一种编程风格,它专注于构建对事件做出响应的应用程序。Spring5包含响应流和Reactor(Reactive Stream的Java实现),响应流和Reactor支撑了Spring自身的功能及相关API。
5. 支持函数式Web框架
Spring5提供了一个函数式Web框架。该框架使用函数式编程风格来定义端点,它引入了两个基本组件:HandlerFunction和RouterFunction。HandlerFunction表示处理接收到的请求并生成响应函数;RouterFunction替代了@RequestMapping注解,用于将接收到的请求转发到处理函数。
6. 支持Kotlin
Spring5提供了对Kotlin语言的支持。Kotlin是一种支持函数式编程风格的面向对象语言,它运行在JVM之上,可以让代码更具表现力、简洁性和可读性。有了对Kotlin的支持,开发人员可以进行深度的函数式Spring编程,这拓宽了Spring的应用领域。
7. 提升测试功能
Spring5完全支持JUnit 5 Jupiter,因此可以使用JUnit5编写测试代码。除此之外,Spring5还提供了在Spring TestContext Framework中进行并行测试的扩展。针对响应式编程模型,Spring5引入了支持Spring WebFlux的WebTestClient集成测试。
6.2 Spring的入门程序
下面通过一个简单的入门程序演示Spring框架的使用,该入门程序要求在控制台打印“weew12:欢迎来到Spring”:
(1)在IDEA中创建 ch6 模块,在pom.xml文件中使用到的Spring的4个基础包:spring-core、spring-beans、spring-context和spring-expression。此外,还需要Spring依赖包commons-logging:
<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">
<parent>
<artifactId>heima_ssm_book</artifactId>
<groupId>io.weew12.github</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ch6</artifactId>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>5.3.31</spring.version>
<common.logging.version>1.2</common.logging.version>
</properties>
<dependencies>
<!--Spring 的基础包 spring-core-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<!--Spring 的基础包 spring-beans-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<!--Spring 的基础包 spring-context-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!--Spring 的基础包 spring-expression-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<!--Spring 的依赖包 commons-logging-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>${common.logging.version}</version>
</dependency>
</dependencies>
</project>(2)在src/main/java/io/weew12/github/HelloSpring.java创建名称为HelloSpring的类,定义userName属性和show()方法:
package io.weew12.github;
public class HelloSpring {
private String userName;
public void setUserName(String userName) {
this.userName = userName;
}
public void show() {
System.out.println(userName + ":欢迎来到Spring");
}
}(3)在src/main/resources下,新建applicationContext.xml文件作为HelloSpring类的配置文件,并在配置文件中创建id为helloSpring的Bean:
<?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,让 Spring 创建 HelloSpring 对象的实例 -->
<bean id="helloSpring" class="io.weew12.github.HelloSpring">
<!-- 为 userName 属性赋值 -->
<property name="userName" value="weew12"/>
</bean>
</beans>在文件中,通过<bean>元素配置HelloSpring类,id属性用于标识HelloSpring类的实例名为helloSpring,class属性指定待实例化的全路径类名为io.weew12.github.HelloSpring。<property>元素为类中的属性赋值,name属性指定HelloSpring类中的属性为userName,value属性指定userName的值为“weew12”。
applicationContext.xml文件包含了很多约束信息,如第2~5行代码就是Spring的约束配置,如果自己动手去编写,浪费时间,容易出错,在Spring的帮助文档中,就可以找到这些约束信息,具体的获取方法如下:
https://docs.spring.io/spring-framework/reference/core/appendix/xsd-schemas.html
其他模块类似参考官方文档进行查找。
(4)在项目文件夹下创建测试类TestHelloSpring,在main()方法中初始化Spring容器并加载applicationContext.xml配置文件,通过Spring容器获取HelloSpring类的helloSpring实例,然后调用HelloSpring类中的show()方法在控制台输出信息:
package io.weew12.github;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestHelloSpring {
public static void main(String[] args) {
// 初始化 Spring 容器,加载 applicationContext.xml 配置
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 通过容器获取配置中 helloSpring 实例
HelloSpring helloSpring = applicationContext.getBean("helloSpring", HelloSpring.class);
// 调用方法
helloSpring.show();
}
}在IDEA中启动测试类TestHelloSpring,控制台的输出结果如图所示。

如图所示,控制台已成功输出了HelloSpring类中show()方法的输出语句。在main()方法中,并没有通过关键字**new**创建HelloSpring类的对象,而是通过Spring容器获取实体类对象,这就是Spring IoC容器的实现机制。
6.3 控制反转与依赖注入
6.3.1 控制反转的概念
控制反转(IoC)是面向对象编程中的一个设计原则,用于降低程序代码之间的耦合度。
在传统面向对象编程中,获取对象的方式是用关键字new主动创建一个对象,也就是说,应用程序掌握着对象的控制权。传统面向对象编程的设计原则如图6-7所示。

图6-7 传统面向对象编程的设计原则
由图6-7可知,在传统面向对象编程中,应用程序是主动创建相关的对象,然后再将对象组合使用,这样会导致类与类之间高耦合,并且难以测试。
在使用Spring框架之后,对象的实例不再由调用者来创建,而是由Spring的IoC容器来创建,IoC容器会负责控制程序之间的关系,而不是由调用者的程序代码直接控制。这样,控制权由应用代码转移到了IoC容器,控制权发生了反转,这就是Spring的控制反转。
IoC设计原则是借助于IoC容器实现具有依赖关系对象之间的解耦,各个对象类封装之后,通过IoC容器来关联这些对象类。这样对象类与对象类之间就通过IoC容器进行联系,而对象类与对象类之间没有直接联系。IoC设计原则如图6-8所示。

图6-8 loC设计原则
在图6-8中,应用程序引入IoC容器之后,在客户端类中将不再创建对象类,而是直接从IoC容器中获取所需的对象类。
6.3.2 依赖注入的概念
依赖注入(Dependency Injection,DI)是指IoC容器在运行期间动态地将某种依赖资源注入到对象中。例如,将对象B注入(赋值)给对象A的成员变量。依赖注入的基本思想是,明确地定义组件接口,独立开发各个组件,然后根据组件的依赖关系组装运行。
依赖注入(DI)和控制反转(IoC)是从不同角度来描述同一件事情。依赖注入是从应用程序的角度描述,即应用程序依赖IoC容器创建并注入它所需要的外部资源;而控制反转是从IoC容器的角度描述,即IoC容器控制应用程序,由IoC容器反向地向应用程序注入应用程序所需要的外部资源。这里所说的外部资源可以是外部实例对象,也可以是外部文件对象等。
6.3.3 依赖注入的类型
依赖注入指的是使用Spring框架创建对象时,动态地将其所依赖的对象注入到Bean组件中。依赖注入通常有两种实现方式,一种是构造方法注入,另一种是属性setter方法注入。
1. 构造方法注入
构造方法注入是指Spring容器调用构造方法注入被依赖的实例,构造方法可以是有参的或者是无参的。Spring在读取配置信息后,会通过反射方式调用实例的构造方法,如果是有参构造方法,可以先在构造方法中传入所需的参数值,然后创建类对象。
下面通过案例演示构造方法注入的实现,具体步骤如下。
(1)编写用户类
在项目新建User1类,在User1类中定义id、name和password这3个属性:
package io.weew12.github;
public class User1 {
private int id;
private String name;
private String password;
/**
* 有参构造方法
*/
public User1(int id, String name, String password) {
this.id = id;
this.name = name;
this.password = password;
}
@Override
public String toString() {
return "User1{" +
"id=" + id +
", name='" + name + '\'' +
", password='" + password + '\'' +
'}';
}
}在文件中,定义了id成员变量、name成员变量和password成员变量;定义了User1的构造方法;定义了toString()方法,当Spring通过构造方法注入相应的值后,toString()方法可以获取这些注入的值。
(2)配置Bean的信息
在项目下创建applicationContext-User.xml文件,在该文件中添加User1类的配置信息:
<?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 id="user1" class="io.weew12.github.User1">
<constructor-arg name="id" value="1"/>
<constructor-arg name="name" value="weew12"/>
<constructor-arg name="password" value="123"/>
</bean>
</beans>在文件中,<constructor-arg>元素用于给User1类构造方法的参数注入值,Spring通过User1类的构造方法获取<constructor-arg>元素定义的值,最终这些值会被赋值给Spring创建的User1对象。
需要注意的是,一个<constructor-arg>元素表示构造方法的一个参数,且定义时不区分顺序,只需要通过<constructor-arg>元素的name属性指定参数即可。<constructor-arg>元素还提供了type属性用于指定参数的类型,避免了字符串和基本数据类型的混淆。
(3)编写测试类
在项目包下创建测试类TestUser1:
package io.weew12.github;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUser1 {
public static void main(String[] args) {
// 加载 applicationContext-User.xml 配置
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext-User.xml");
// 获取配置中的 User1 实例
User1 user1 = applicationContext.getBean("user1", User1.class);
System.out.println(user1);
}
}运行文件中的main()方法,运行结果如图所示。

如图所示,控制台输出了User1实例的信息,其中成员变量的值与配置文件中<constructor-arg>元素的value值相同,由此可知,Spring实现了构造方法注入。
2. 属性setter方法注入
属性setter方法注入是Spring最主流的注入方法,这种注入方法简单、直观,它是在被注入的类中声明一个setter方法,通过setter方法的参数注入对应的值。
下面通过一个案例演示属性setter方法注入的实现,具体步骤如下。
(1)编写用户对象类
在项目下新建User2类,在User2类中定义id、name和password这3个属性:
package io.weew12.github;
public class User2 {
private int id;
private String name;
private String password;
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User2{" +
"id=" + id +
", name='" + name + '\'' +
", password='" + password + '\'' +
'}';
}
}在文件中,定义了id成员变量、name成员变量和password成员变量;定义了setter方法和toString()方法。当Spring通过属性注入相应的值后,通过toString()方法可以获取这些注入的值。
(2)配置Bean信息
在项目下创建applicationContext-User2.xml文件,并在该文件的<bean>元素中添加User2类的配置信息:
<?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 id="user2" class="io.weew12.github.User2">
<property name="id" value="2"/>
<property name="name" value="weew13"/>
<property name="password" value="456"/>
</bean>
</beans>在文件6-9中,<property>元素的name属性指定该类的成员变量名称,value属性提供对应的成员变量注入值。
(3)编写测试类
在项目下创建测试类TestUser2:
package io.weew12.github;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUser2 {
public static void main(String[] args) {
// 加载applicationContext-User2.xml配置
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext-User2.xml");
// 获取配置中创建的User2实例类
User2 user2 = applicationContext.getBean("user2", User2.class);
System.out.println(user2);
}
}运行结果如图所示。

如图所示,控制台输出了User2实例的信息,其中成员变量的值与配置文件中<property>元素的value值相同。由此可知,Spring实现了属性setter方法注入。
6.3.4 依赖注入的应用
在了解了两种注入方式后,下面以属性setter方法注入为例,实现一个简单的登录验证,具体实现步骤如下。
1. 编写DAO层
在项目下新建dao包,在dao包下创建接口UserDao,在UserDao接口中添加login()方法,用于实现登录功能:
package io.weew12.github.dao;
public interface UserDao {
/**
* 登陆功能接口
*/
boolean login(String name, String password);
}在dao包下创建impl包,在Impl包下创建UserDao接口的实现类UserDaoImpl,在UserDaoImpl类中实现login()方法:
package io.weew12.github.dao.Impl;
import io.weew12.github.dao.UserDao;
public class UserDaoImpl implements UserDao {
@Override
public boolean login(String name, String password) {
return "weew12".equals(name) && "123".equals(password);
}
}本案例并没有使用到数据库,在文件中,login()方法判断用户名是否为weew12且密码是否为123,若均是则登录信息验证成功。
2. 编写Service层
在项目包下新建service包,在service包下创建接口UserService,在接口中添加login()方法:
package io.weew12.github.service;
public interface UserService {
boolean loginService(String name, String password);
}在service包下创建Impl包,在 Impl包下创建UserService接口的实现类UserServiceImpl,在UserServiceImpl类中实现login()方法:
package io.weew12.github.service.Impl;
import io.weew12.github.dao.UserDao;
import io.weew12.github.service.UserService;
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public boolean loginService(String name, String password) {
return userDao.login(name, password);
}
}在文件中,没有采用传统的关键字new方式获取数据访问层UserDaoImpl类的实例,而是使用UserDao接口声明对象userDao,并为其添加setter方法,用于依赖注入。UserDaoImpl类的实例化和对象userDao的注入将在applicationContext.xml配置文件中完成。
3. 编写applicationContext.xml配置文件
在文件中添加两个<bean>元素,分别用于配置UserDaoImpl类和UserServiceImpl类的实例及相关属性,具体代码如下:
<?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">
......
<!-- 配置UserDaoImpl实例 -->
<bean id="userDao" class="io.weew12.github.dao.Impl.UserDaoImpl"/>
<!-- 配置UserServiceImpl实例,并注入userDao依赖 -->
<bean id="userService" class="io.weew12.github.service.Impl.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
</beans>在上述代码中,首先通过一个<bean>元素创建UserDaoImpl类的实例,再使用另一个<bean>元素创建UserServiceImpl类的实例时,使用了<property>元素,该元素是<bean>元素的子元素,用于调用Bean实例中的相关setter方法完成属性值的赋值,从而实现依赖关系的注入。<property>元素中的name属性指定Bean实例中的相应属性的名称,这里将name属性设置为userDao,表示UserServiceImpl类中的userDao属性需要注入值。name属性的值可以通过ref属性或者value属性指定。当使用ref属性时,表示对Spring IoC容器中某个Bean实例的引用。这里引用了前一个<bean>元素中创建的UserDaoImpl类的实例userDao,并将该实例赋值给UserServiceImpl类中的userDao属性,从而实现了依赖关系的注入。
4. 编写测试类
新建测试类TestSpring:
package io.weew12.github;
import io.weew12.github.service.UserService;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring {
public static void main(String[] args) {
// 加载applicationContext.xml配置
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取配置中的UserService实例
UserService userService = applicationContext.getBean("userService", UserService.class);
boolean result = userService.loginService("weew12", "123");
validate(result);
boolean result2 = userService.loginService("weew12", "1233");
validate(result2);
}
public static void validate(boolean result) {
if (result) {
System.out.println("登录成功");
} else {
System.out.println("登录失败");
}
}
}在文件中,通过ClassPathXmlApplicationContext类加载Spring配置文件applicationContext.xml;从配置文件中获取UserService类的实例;调用login()方法。

6.4 本章小结
本章主要讲解了Spring框架的基础知识,首先介绍了Spring框架基础知识,包括Spring概述、Spring框架的优点、Spring框架的体系结构、Spring5的新特性和Spring下载;然后编写了Spring的入门程序;最后讲解了控制反转与依赖注入,包括控制反转的概念、依赖注入的概念、依赖注入的类型和依赖注入的应用。通过学习本章的内容,读者可以对Spring框架有个大致的了解,为框架开发打下基础。
【思考题】
- 请简述Spring框架的优点。
Spring框架是Java领域中最受欢迎的企业级应用开发框架之一,它具有许多显著的优势:
- 轻量级:Spring框架的核心是一个轻量级的控制反转(IoC)容器,它使用依赖注入(DI)来管理应用程序中的对象及其依赖关系。这使得开发者可以更加专注于业务逻辑而不是底层的技术细节。
- 面向切面编程(AOP)支持:Spring提供了一套完整的AOP解决方案,能够帮助开发者更好地处理横切关注点,如事务管理、日志记录等,从而提高代码复用性和模块化程度。
- 声明式事务管理:通过Spring的事务管理机制,开发者可以很容易地定义和配置事务边界,而无需编写复杂的事务控制代码。
- 良好的可扩展性:Spring设计时就考虑到了灵活性与可扩展性,它允许用户自定义各种组件,并且易于与其他技术集成。
- 丰富的生态系统:围绕着Spring发展出了一个庞大的社区和生态系统,提供了大量的插件、库以及工具支持,覆盖了从Web开发到大数据处理等多个领域。
- 请简述控制反转的概念和依赖注入的概念。
- 控制反转(Inversion of Control, IoC) 是一种设计原则,其核心思想是将对象创建及管理的权利交给外部容器或框架,而不是由应用程序自身来负责。这样做的好处是可以降低系统中各组件之间的耦合度,提高软件系统的灵活性和可测试性。在传统的程序设计模式下,高层次的模块通常会直接调用低层次模块;而在IoC模式下,则是由容器根据配置文件或其他方式决定如何组装这些模块。
- 依赖注入(Dependency Injection, DI) 是实现控制反转的一种具体手段,它指的是在一个对象被创建时,不是由这个对象自己去获取它所依赖的对象实例,而是由外部(通常是容器)将这些依赖项传递给该对象。这种做法有助于解耦合,因为各个类不再需要知道它们所依赖的具体实现是什么样的,只需要关心接口即可。依赖注入可以通过构造函数注入、设值方法注入(setter injection) 或者字段注入等方式实现。在Spring框架中,依赖注入是实现控制反转的主要方式之一。
