使用 Spring 构建班级名册应用
1. 引言
在开发班级名册应用时,我们可以借助 Spring 框架来实现依赖注入和应用程序的连接。使用 Spring DI 容器是 Spring 开发的基础技能,几乎所有其他 Spring 特性(如安全、AOP、MVC、REST)都依赖于核心的 Spring DI 容器。接下来,我们将详细介绍如何将班级名册应用转换为 Spring 应用。
2. 项目目标
为了将班级名册应用转换为 Spring 应用,我们需要完成以下任务:
- 添加 Spring 库到 POM 文件
- 添加 Spring 配置文件到项目
- 将 App 类中的依赖注入和应用连接代码转换为使用 Spring
- 将单元测试转换为使用 Spring
3. 包含 Spring 库
要使用 Spring 框架,我们需要确保 Maven POM 文件中包含 Spring 框架库。打开
pom.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.sg</groupId>
<artifactId>ClassRoster</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.6.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.6.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.6.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
</project>
特别要检查以下依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.0.RELEASE</version>
</dependency>
只要 Spring 框架依赖在
<dependencies>
节点内,即使各个依赖的顺序不同,也不会有问题。
如何确定依赖项
有两种方法可以确定 Maven 依赖项:
-
访问项目网站
:许多项目网站会直接提供 Maven 依赖项,只需复制粘贴到 POM 文件即可。例如,Spring 核心框架的 Maven 条目可以在 Spring Boot 的 Maven 插件页面(docs.spring.io/spring-boot/docs/current/maven-plugin/usage.html)找到。
-
使用搜索引擎搜索
:例如,在 Google 上搜索 “JUnit maven dependency”,搜索结果的顶部通常会有 JUnit 5 的 Maven 依赖项页面(mvnrepository.com/artifact/junit/junit/)。
4. 添加 Spring 配置文件
在引入 Spring 库后,我们需要添加应用程序上下文配置文件。一种定义 Spring DI 容器和应用程序上下文的方法是使用 XML 配置文件。我们通常将所有 bean 定义在
applicationContext.xml
文件中,但这不是强制要求,你可以使用任何文件名。
操作步骤如下:
1. 在项目的
src/main/resources
文件夹中创建
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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Bean definitions go here -->
</beans>
这是一个空的
applicationContext
文件模板,预填充了 Spring 容器的 XML 命名空间条目和一些额外的 Spring 特性。所有 bean 连接定义将出现在 “Bean definitions go here” 注释之后和
</beans>
标签之前。
-
在项目的
src/test/resources文件夹中执行相同的操作(可能需要手动创建该文件夹)。这个applicationContext.xml文件将用于单元测试的单独配置。
5. 将 App 类转换为使用 Spring
现在,我们要将 App 类中的手动依赖注入代码转换为使用 Spring 进行依赖注入。具体来说,我们将把 App 类
main
方法中的代码移动到
applicationContext.xml
文件中。
App 类的
main
方法原始代码如下:
public static void main(String[] args) {
UserIO myIo = new UserIOConsoleImpl();
ClassRosterView myView = new ClassRosterView(myIo);
ClassRosterDao myDao = new ClassRosterDaoFileImpl();
ClassRosterAuditDao myAuditDao = new ClassRosterAuditDaoFileImpl();
ClassRosterServiceLayer myService = new ClassRosterServiceLayerImpl(myDao, myAuditDao);
ClassRosterController controller = new ClassRosterController(myService, myView);
controller.run();
}
定义 Bean
在修改
applicationContext.xml
文件之前,我们需要了解一些用于定义 bean 的标签和属性:
-
bean 标签
:用于定义我们希望 Spring 容器实例化的对象。
-
id 属性
:用于为 Spring 容器实例化的特定 bean 指定别名,类似于 Map 中的键。
-
class 属性
:指定我们希望 Spring 容器实例化的类的完全限定名,必须包含完整的包名。
-
constructor-arg 标签
:嵌套在 bean 标签中,用于指示 Spring 在实例化 bean 时将参数传递给构造函数。
-
ref 属性
:用于引用之前定义的 bean,其值必须是
applicationContext.xml
文件中另一个 bean 的 id。
修改
src/main/resources
中的
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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Bean definitions go here -->
<bean id="userIO" class="com.sg.classroster.ui.UserIOConsoleImpl"/>
<bean id="view" class="com.sg.classroster.ui.ClassRosterView">
<constructor-arg ref="userIO"/>
</bean>
<bean id="classRosterDao" class="com.sg.classroster.dao.ClassRosterDaoFileImpl"/>
<bean id="auditDao" class="com.sg.classroster.dao.ClassRosterAuditDaoFileImpl"/>
<bean id="serviceLayer" class="com.sg.classroster.service.ClassRosterServiceLayerImpl">
<constructor-arg ref="classRosterDao"/>
<constructor-arg ref="auditDao"/>
</bean>
<bean id="controller" class="com.sg.classroster.controller.ClassRosterController">
<constructor-arg ref="serviceLayer"/>
<constructor-arg ref="view"/>
</bean>
</beans>
修改 App 类
修改 App 类的
main
方法,替换为以下代码:
public static void main(String[] args) {
// 注释掉原有的手动实例化代码
// UserIO myIo = new UserIOConsoleImpl();
// ClassRosterView myView = new ClassRosterView(myIo);
// ClassRosterDao myDao = new ClassRosterDaoFileImpl();
// ClassRosterAuditDao myAuditDao = new ClassRosterAuditDaoFileImpl();
// ClassRosterServiceLayer myService = new ClassRosterServiceLayerImpl(myDao, myAuditDao);
// ClassRosterController controller = new ClassRosterController(myService, myView);
// controller.run();
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ClassRosterController controller = ctx.getBean("controller", ClassRosterController.class);
controller.run();
}
ApplicationContext
是保存
applicationContext.xml
文件中定义的应用程序上下文的 Java 对象。我们使用
ClassPathXmlApplicationContext
实现,并将 Spring 应用程序上下文配置文件的名称传递给其构造函数。通过
getBean
方法可以从 Spring 应用程序上下文中检索 bean,该方法接受两个参数:要检索的 bean 的 id 和 bean 的类型。
6. 转换单元测试以使用 Spring
我们只需要将服务层单元测试转换为使用 Spring 应用程序上下文,因为只有服务层使用了依赖注入。
操作步骤如下:
1. 将
ClassRosterServiceLayerTest
类构造函数中的代码移动到
applicationContext.xml
文件中。
ClassRosterServiceLayerTest
类的构造函数原始代码如下:
public ClassRosterServiceLayerTest() {
// wire the Service Layer with stub implementations of the Dao and
// Audit Dao
ClassRosterDao dao = new ClassRosterDaoStubImpl();
ClassRosterAuditDao auditDao = new ClassRosterAuditDaoStubImpl();
service = new ClassRosterServiceLayerImpl(dao, auditDao);
}
-
修改
src/test/resources中的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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Bean definitions go here -->
<bean id="classRosterDao" class="com.sg.classroster.dao.ClassRosterDaoFileImpl"/>
<bean id="classRosterDaoStub" class="com.sg.classroster.dao.ClassRosterDaoStubImpl"/>
<bean id="auditDaoStub" class="com.sg.classroster.dao.ClassRosterAuditDaoStubImpl"/>
<bean id="serviceLayer" class="com.sg.classroster.service.ClassRosterServiceLayerImpl">
<constructor-arg ref="classRosterDaoStub"/>
<constructor-arg ref="auditDaoStub"/>
</bean>
</beans>
与应用程序本身的
applicationContext.xml
文件相比,这里只定义了 DAO 和服务层的 bean,并且使用了存根版本的 DAO。
-
修改
ClassRosterServiceLayerTest类的构造函数:
public ClassRosterServiceLayerTest() {
// 注释掉原有的手动实例化代码
// wire the Service Layer with stub implementations of the Dao and
// Audit Dao
// ClassRosterDao dao = new ClassRosterDaoStubImpl();
// ClassRosterAuditDao auditDao = new ClassRosterAuditDaoStubImpl();
// service = new ClassRosterServiceLayerImpl(dao, auditDao);
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
service = ctx.getBean("serviceLayer", ClassRosterServiceLayer.class);
}
7. 异常情况
虽然 Spring 容器可以帮助我们构建灵活、松散耦合的应用程序,但将依赖项外部化到 XML 配置文件可能会导致一些运行时错误,因为编译器无法捕获这些错误。以下是一些常见的错误:
| 错误类型 | 描述 |
| ---- | ---- |
| 拼写错误的 bean 类属性 | 所有 bean 类必须使用正确拼写的完全限定类名,否则 Spring 容器将抛出错误,指示无法实例化该 bean。 |
| ref 属性中 bean id 拼写错误 | 在 ref 属性中引用另一个 bean 时,其名称必须与原始 bean 定义中的名称完全一致。 |
| 格式错误的 XML |
applicationContext.xml
文件必须是格式良好的 XML,此类错误通常会在错误消息中指出发生错误的行和列。 |
| 错误使用 value 属性 | 在构造函数或 setter 注入中,应使用 ref 属性传递对象引用,而不是使用 value 属性传递字面量值。 |
这些错误消息会显示在 NetBeans 控制台输出中。另外,还可以使用注解或 Java 代码为 Spring 容器提供配置元数据,这两种方式可以更好地处理上述错误,因为元数据是用 Java 代码编写的。
以下是将班级名册应用转换为 Spring 应用的流程图:
graph LR
A[添加 Spring 库到 POM 文件] --> B[添加 Spring 配置文件]
B --> C[将 App 类转换为使用 Spring]
C --> D[转换单元测试以使用 Spring]
通过以上步骤,我们可以将班级名册应用成功转换为使用 Spring 框架的应用程序,利用 Spring 的依赖注入和应用程序连接功能,提高代码的可维护性和可测试性。
使用 Spring 构建班级名册应用
8. 总结关键步骤
为了更清晰地回顾整个将班级名册应用转换为 Spring 应用的过程,我们将关键步骤总结如下:
| 步骤 | 操作内容 |
|---|---|
| 1 |
包含 Spring 库:在
pom.xml
文件中添加 Spring 相关依赖,可通过项目网站或搜索引擎确定依赖项。
|
| 2 |
添加 Spring 配置文件:在
src/main/resources
和
src/test/resources
文件夹中分别创建
applicationContext.xml
文件,并使用预定义的模板。
|
| 3 |
转换 App 类:将 App 类
main
方法中的手动依赖注入代码迁移到
applicationContext.xml
文件,修改
main
方法以使用 Spring 容器实例化对象。
|
| 4 |
转换单元测试:将服务层单元测试的构造函数代码迁移到
src/test/resources
中的
applicationContext.xml
文件,修改测试类构造函数以使用 Spring 容器。
|
| 5 | 处理异常情况:注意常见的 XML 配置文件错误,如 bean 类属性拼写错误、ref 属性中 bean id 拼写错误等。 |
9. 代码解释与分析
App 类转换代码分析
在 App 类的
main
方法中,我们从手动实例化对象转变为使用 Spring 容器。原代码通过手动创建每个对象并传递依赖,而修改后的代码使用
ClassPathXmlApplicationContext
加载
applicationContext.xml
文件,并通过
getBean
方法从容器中获取所需的对象。
// 原代码
public static void main(String[] args) {
UserIO myIo = new UserIOConsoleImpl();
ClassRosterView myView = new ClassRosterView(myIo);
ClassRosterDao myDao = new ClassRosterDaoFileImpl();
ClassRosterAuditDao myAuditDao = new ClassRosterAuditDaoFileImpl();
ClassRosterServiceLayer myService = new ClassRosterServiceLayerImpl(myDao, myAuditDao);
ClassRosterController controller = new ClassRosterController(myService, myView);
controller.run();
}
// 修改后代码
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ClassRosterController controller = ctx.getBean("controller", ClassRosterController.class);
controller.run();
}
这样做的好处是将对象的创建和依赖管理从代码中分离出来,提高了代码的可维护性和可测试性。当需要更改依赖关系时,只需要修改
applicationContext.xml
文件,而不需要修改 Java 代码。
单元测试转换代码分析
在服务层单元测试中,同样将手动实例化对象的代码迁移到
applicationContext.xml
文件。原代码在构造函数中手动创建 DAO 和服务层对象,而修改后的代码使用 Spring 容器获取服务层对象。
// 原代码
public ClassRosterServiceLayerTest() {
ClassRosterDao dao = new ClassRosterDaoStubImpl();
ClassRosterAuditDao auditDao = new ClassRosterAuditDaoStubImpl();
service = new ClassRosterServiceLayerImpl(dao, auditDao);
}
// 修改后代码
public ClassRosterServiceLayerTest() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
service = ctx.getBean("serviceLayer", ClassRosterServiceLayer.class);
}
这种方式使得单元测试更加灵活,因为可以通过修改
applicationContext.xml
文件轻松更换 DAO 的实现,例如使用存根版本进行测试。
10. 深入理解 Spring 配置文件
applicationContext.xml
文件是 Spring 应用的核心配置文件,其中定义了各个 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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Bean definitions go here -->
<bean id="userIO" class="com.sg.classroster.ui.UserIOConsoleImpl"/>
<bean id="view" class="com.sg.classroster.ui.ClassRosterView">
<constructor-arg ref="userIO"/>
</bean>
<bean id="classRosterDao" class="com.sg.classroster.dao.ClassRosterDaoFileImpl"/>
<bean id="auditDao" class="com.sg.classroster.dao.ClassRosterAuditDaoFileImpl"/>
<bean id="serviceLayer" class="com.sg.classroster.service.ClassRosterServiceLayerImpl">
<constructor-arg ref="classRosterDao"/>
<constructor-arg ref="auditDao"/>
</bean>
<bean id="controller" class="com.sg.classroster.controller.ClassRosterController">
<constructor-arg ref="serviceLayer"/>
<constructor-arg ref="view"/>
</bean>
</beans>
-
bean 标签
:每个
bean标签代表一个要由 Spring 容器管理的对象。id属性是该 bean 的唯一标识符,class属性指定了该 bean 的具体实现类。 -
constructor-arg 标签
:用于在创建 bean 时传递构造函数参数。
ref属性表示引用另一个已定义的 bean,通过这种方式可以建立 bean 之间的依赖关系。
11. 异常处理的最佳实践
为了避免在运行时出现配置文件相关的错误,我们可以遵循以下最佳实践:
-
仔细检查类名和 id
:在编写
applicationContext.xml文件时,确保所有 bean 的类名和 id 拼写正确,特别是在使用ref属性引用其他 bean 时。 -
验证 XML 格式
:使用 XML 验证工具或 IDE 的 XML 验证功能,确保
applicationContext.xml文件的格式正确。 -
使用注解或 Java 配置
:考虑使用注解(如
@Component、@Autowired)或 Java 代码(如@Configuration类)来配置 Spring 容器,这样可以在编译时捕获更多错误。
12. 后续扩展与优化建议
将班级名册应用转换为 Spring 应用只是一个开始,我们可以在此基础上进行更多的扩展和优化:
- 引入 Spring Boot :Spring Boot 可以简化 Spring 应用的开发和部署,提供自动配置和嵌入式服务器等功能。
- 添加安全功能 :使用 Spring Security 为应用添加身份验证和授权功能,保护应用的敏感数据和接口。
- 实现 RESTful API :利用 Spring MVC 或 Spring WebFlux 实现 RESTful API,使应用可以与其他系统进行交互。
以下是一个扩展功能的流程图:
graph LR
A[现有 Spring 班级名册应用] --> B[引入 Spring Boot]
B --> C[添加 Spring Security 安全功能]
C --> D[实现 RESTful API]
通过以上步骤和建议,我们不仅成功将班级名册应用转换为 Spring 应用,还为应用的进一步发展和优化奠定了基础。在实际开发中,可以根据项目的具体需求选择合适的扩展方向,不断提升应用的性能和功能。
超级会员免费看

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



