Spring 框架
了解一些关于Spring框架的面试问题。
Spring 5 的主要特性有哪些?
Spring 5 于 2017 年发布,其主要特性包括:
- 最低要求 Java 8。
- 支持使用 Lambda 表达式。
- 基于 Servlet 4.0 API。
- 内置响应式编程框架 WebFlux。
- 支持 Kotlin 用于函数式编程。
- 提供对 JUnit 5 测试框架的支持。
Spring 5 是否兼容旧版本的 Java?
不兼容。因为 Spring 5 要求最低 Java 8 版本。由于 Spring 框架代码库已全面重构以利用 Java 8 的新特性,因此不再支持旧版本的 Java。
使用 Spring 框架的优势有哪些?
- Spring 框架是开源的。
- Spring 框架设计初衷是为了减少样板代码。
- 依赖注入使得代码松耦合,便于修改和维护。
- Spring 架构具有模块化特性,使其成为一个轻量级框架。开发者可根据需要选择仅引入应用所需的模块。
- Spring 与 Hibernate、Struts、EJB 等多种框架有良好的集成支持。
- 自动配置功能可显著缩短开发时间,开发者只需关注业务逻辑,Spring 会自动处理配置细节。
- Spring 支持面向切面编程(AOP),将业务逻辑与系统服务分离。
- Spring 提供了将特定技术异常转换为未检查异常的 API。
- Spring 支持可测试代码和测试驱动开发(TDD)。
列出 Spring 框架的模块
Spring 架构是模块化的,各模块可根据功能进行分组:
- Spring 核心容器包含 Core、Beans、Context 和表达式语言(SpEL)模块。
- 数据访问或集成层包含 JDBC、ORM、OXM、JMS 和事务模块。
- Web 层包含 Web、Servlet、Portlet、Struts 等模块。
- 其他模块包括 Test、AOP、Aspects 和 Instrumentation。
什么是紧耦合?
当两个类相互依赖时,例如类 A 需要类 B 的实例,则称它们之间存在耦合。紧耦合是指类 A 直接创建类 B 的实例。在这种情况下,若想用另一个类替换类 B,就必须修改类 A 的代码。
例如,Vehicle 类依赖于 CombustionEngine 类,并通过如下方式创建其实例:
1class Vehicle { 2 private CombustionEngine engine = new CombustionEngine(); 3 // ... 4}
如果希望从 CombustionEngine 替换为 ElectricEngine,则必须修改 Vehicle 类的代码。
什么是松耦合?
松耦合消除了类对具体对象的依赖。这通过引入接口实现。现在类 A 依赖于一个接口,该接口有两个实现:类 B 和类 C。可以通过设置方法或构造函数传入接口类型的对象来注入依赖。这样,在不修改类 A 代码的前提下,可以轻松切换实现类 B 或类 C。
例如,Engine 是 Vehicle 的依赖。我们可以定义一个 Engine 接口,并提供两个实现:CombustionEngine 和 ElectricEngine。
1interface Engine { 2 // ... 3}
CombustionEngine 类实现 Engine 接口:
1class CombustionEngine implements Engine { 2 // ... 3}
ElectricEngine 类也实现 Engine 接口:
1class ElectricEngine implements Engine { 2 // ... 3}
此时 Vehicle 与 Engine 之间实现了松耦合。在 Vehicle 类中,无需修改代码即可使用任意类型的引擎。
1class Vehicle { 2 private Engine engine; 3 4 Vehicle(Engine engine) { 5 this.engine = engine; 6 } 7 // ... 8}
application.properties 文件的作用是什么?
application.properties 文件用于配置应用程序在不同环境下的属性值。可用于配置数据库连接信息、日志生成等。
该文件位于 src/main/resources 目录下。
什么是 pom.xml 文件?
POM 代表项目对象模型(Project Object Model)。它是 Maven 项目中的一个 XML 配置文件,用于定义项目的配置信息。<dependency> 标签列出了所有依赖项,并通过 <groupId>、<artifactId>、<version> 和 <packaging> 等标签提供依赖的详细信息。Maven 依据 pom.xml 中的信息构建项目。
Spring 框架中使用了哪些设计模式?
Spring 框架使用了多种设计模式:
- 工厂模式:BeanFactory 和 ApplicationContext 类。
- 单例模式:作用域为 singleton 的 Bean。
- 原型模式:作用域为 prototype 的 Bean。
- 代理模式:支持 Spring 的面向切面编程(AOP)。
- 模板方法模式:如 JdbcTemplate、JmsTemplate、JpaTemplate 等。
- 数据访问对象模式:Spring DAO 支持。
- 模型视图控制器模式:Spring MVC。
- 前端控制器模式:Spring MVC 中的 DispatcherServlet。
- 视图辅助模式:自定义 JSP 标签将代码与视图展示分离。
- 适配器模式:Spring Integration 中的 JMS 和 JDBC 适配器。
Spring 框架的一些最佳实践有哪些?
- 仅使用应用实际需要的模块,移除因使用 Spring Tools Suite 自动生成的多余模块。
- 根据应用层次合理使用注解:
@Service用于业务逻辑层,@Repository用于数据访问层。 - 创建外部属性文件来管理配置属性。
- 使用 Spring Initializr 创建新的 Spring Boot 项目,以获得经过验证和推荐的依赖集合,节省配置时间。
- 使用 Controller 类将业务逻辑委托给服务层。
- 使用日志框架替代手动打印,避免使用
System.out.println()。
描述一些标准的 Spring 事件。
事件机制为松耦合组件之间提供了通信方式。Spring 应用上下文(ApplicationContext)在其生命周期中会发布若干事件。
标准的 Spring 事件包括:
ContextStartedEvent:当上下文启动时触发。ContextRefreshedEvent:当上下文被初始化或通过refresh()方法刷新时触发。ContextStoppedEvent:当上下文通过stop()方法停止时触发。ContextClosedEvent:当对 ApplicationContext 调用close()方法时触发。RequestHandledEvent:通知所有 Bean 一个 HTTP 请求已被处理。
Spring 5 如何利用 JDK 9 模块化?
Java 9 引入了模块,即一组相关的包、资源文件(如 XML)以及描述模块名称、依赖关系和可公开使用的包的模块描述符。Spring 5 利用 JDK 9 模块化机制,提升了性能、安全性,并增强了依赖管理的可靠性。
Spring 5 具备以下利用 JDK 9 模块化特性的功能:
- Spring 5 使用 Java 平台模块系统(JPMS),即 JDK 9 引入的模块化系统,对框架本身进行模块化。Spring 5 被组织为多个模块,每个模块拥有独立的依赖关系。
spring-core模块专为 JPMS 设计,定义了核心 Spring API,并进一步划分为多个子模块,对应不同的功能区域。spring-context模块(同样支持 JPMS)定义了 Spring 容器,并提供对基于注解的编程模型的支持。spring-boot-loader模块(支持 JPMS)负责在模块化环境中加载并启动 Spring Boot 应用。- Spring 5 支持在模块路径(module path)上运行,而非传统的类路径(classpath)。这意味着 Spring 应用可以充分利用 JPMS 提供的封装性增强和更优的运行时性能。
示例
一个 Spring 5 项目可以围绕这一概念构建。假设我们有一个位于 io.datajek.jdkmodularity 包中的 ModuleExample 类。
1package io.datajek.jdkmodularity; 2 3public class ModuleExample { 4 public String displayMessage() { 5 return "Spring 5 与 JDK 9 模块化"; 6 } 7}
为了使该包可供其他包访问,可以将其纳入一个模块。这通过 module 关键字实现。export 关键字用于指定哪些包的公共方法对外部模块可见。
1module io.datajek.modularityexample { 2 exports io.datajek.jdkmodularity; 3}
该模块可在任何其他 Java 项目中通过 requires 关键字使用,表示 io.datajek.modularityexample.demo 模块依赖于 io.datajek.modularityexample 模块。
1module io.datajek.modularityexample.demo { 2 requires io.datajek.modularityexample; 3}
现在,可以在新模块中访问 ModuleExample 类及其公共方法,如下所示:
1public class ModuleExampleExplained { 2 public static void main(String[] args) { 3 ModuleExample moduleExample = new ModuleExample(); 4 moduleExample.displayMessage(); 5 } 6}