跳至主要內容

Spring 面试

钝悟...大约 18 分钟Java框架SpringJava框架Spring面试

Spring 面试

综合篇

【简单】不同版本的 Spring 有哪些主要功能?

VersionFeature
Spring 2.5发布于 2007 年。这是第一个支持注解的版本。
Spring 3.0发布于 2009 年。它完全利用了 Java5 中的改进,并为 JEE6 提供了支持。
Spring 4.0发布于 2013 年。这是第一个完全支持 JAVA8 的版本。

【简单】Spring、SpringMVC、SpringBoot 三者之间是什么关系?

Spring 是一个应用级框架。

Spring MVC 是 Spring 一个子模块,主要支持 Web 领域的开发。

Spring Boot 是基于 Spring 框架,支持各种自动化默认配置,节省接入成本。其设计理念是:约定由于配置。

【简单】什么是 Spring?

  • Spring 是一个开源应用框架,旨在降低应用程序开发的复杂度。
  • 它是轻量级、松散耦合的。
  • 它具有分层体系结构,允许用户选择组件,同时还为 J2EE 应用程序开发提供了一个有凝聚力的框架。
  • 它可以集成其他框架,如 Structs、Hibernate、EJB 等,所以又称为框架的框架。

【简单】列举 Spring Framework 的优点。

  • 由于 Spring Frameworks 的分层架构,用户可以自由选择自己需要的组件。
  • Spring Framework 支持 POJO(Plain Old Java Object) 编程,从而具备持续集成和可测试性。
  • 由于依赖注入和控制反转,JDBC 得以简化。
  • 它是开源免费的。

【中等】Spring 有哪些模块?🌟

img
img

Spring 的核心模块主要包括以下部分:

  • Core Container 模块
    • Spring Core:提供控制反转(IoC)和依赖注入(DI)功能,是 Spring 框架的基础。
    • Spring Beans:管理 Bean 的生命周期和依赖关系,提供 BeanFactory,用于创建和管理对象。
    • Spring Context:建立在 Core 和 Beans 模块之上,提供配置、国际化、事件传播等功能。
    • Spring Expression Language(SpEL):支持运行时查询和操作对象图的表达式语言。
  • AOP 模块
    • Spring AOP:提供面向切面编程的支持,实现横切关注点的模块化,如日志、事务管理。
    • Aspects:与 AspectJ 集成,提供更强大的 AOP 功能。
  • 数据访问/集成模块
    • Spring JDBC:简化 JDBC 操作,提供异常处理和资源管理。
    • Spring ORM:集成主流 ORM 框架,如 Hibernate、JPA,提供统一的 DAO 支持。
    • Spring Transactions:提供声明式和编程式事务管理,确保数据一致性。
  • Web 模块
    • Spring Web:提供 Web 应用程序开发的基础功能,如多部分文件上传。
    • Spring MVC:基于 MVC 设计模式的 Web 框架,支持灵活的视图技术。
    • Spring WebFlux:响应式编程模型,支持非阻塞式 Web 应用。
  • 测试模块
    • Spring Test:提供对单元测试和集成测试的支持,简化测试代码的编写。
  • 其他模块
    • Spring Instrumentation:提供类加载器和类植入支持。
    • Spring Messaging:支持消息传输,如 STOMP 协议和 WebSocket。

这些核心模块共同构成了 Spring 框架的基础,为开发者提供了全面的解决方案,简化了 Java 应用程序的开发。

【中等】Spring 是如何启动的?🌟🌟

Spring 启动主要分为三阶段:

  1. 初始化容器
    • 实例化 ApplicationContext
    • 调用核心的 refresh() 方法,触发启动流程。
  2. 加载解析配置
    • 将配置(XML 或注解)解析为 BeanDefinition 对象。
    • 将所有 BeanDefinition 注册到容器的“注册表”中。
  3. 创建与注入 Bean
    • 实例化所有非懒加载的单例 Bean(调用构造方法)。
    • 进行依赖注入(DI),为 Bean 填充属性。
    • 执行 Bean 的初始化(Aware 接口、BeanPostProcessor、init-method)。

Spring 启动流程可以概括为:容器读取配置,生成 Bean 定义,然后根据定义通过反射创建 Bean 实例,并递归地完成依赖注入和初始化的过程

【中等】Spring 框架中都用到了哪些设计模式?🌟🌟

设计模式Spring 中的应用场景目的
工厂模式BeanFactory, ApplicationContext解耦对象的创建与使用
单例模式Bean 的默认作用域保证一个类只有一个实例
代理模式AOP(如 @Transactional控制对象访问,增强功能
模板方法模式JdbcTemplate, RestTemplate封装固定流程,简化开发
观察者模式应用事件(ApplicationEvent实现事件驱动,解耦组件
策略模式Resource, PlatformTransactionManager封装可互换的算法族
适配器模式HandlerAdapter转换接口,使不兼容的类能合作
装饰者模式HttpServletRequestWrapper动态增强对象功能

Bean

【简单】什么是 Spring Bean?

在 Spring 中,构成应用程序主体由 Spring IoC 容器管理的对象称为 Bean。Bean 是由 Spring IoC 容器实例化、装配和管理的对象。 Bean 以及它们之间的依赖关系反映在容器使用的配置元数据中。

Spring IoC 容器本身,并不能识别配置的元数据。为此,要将这些配置信息转为 Spring 能识别的格式——BeanDefinition 对象。

BeanDefinition 是 Spring 中定义 Bean 的配置元信息接口,它包含:

  • Bean 类名
  • Bean 行为配置元素,如:作用域、自动绑定的模式、生命周期回调等
  • 其他 Bean 引用,也可称为合作者(Collaborators)或依赖(Dependencies)
  • 配置设置,如 Bean 属性(Properties)

【简单】Spring 提供了哪些配置方式?

  • 基于 xml 配置

bean 所需的依赖项和服务在 XML 格式的配置文件中指定。这些配置文件通常包含许多 bean 定义和特定于应用程序的配置选项。它们通常以 bean 标签开头。例如:

<bean id="studentbean" class="org.edureka.firstSpring.StudentBean">
 <property name="name" value="Edureka"></property>
</bean>
  • 基于注解配置

您可以通过在相关的类,方法或字段声明上使用注解,将 bean 配置为组件类本身,而不是使用 XML 来描述 bean 装配。默认情况下,Spring 容器中未打开注解装配。因此,您需要在使用它之前在 Spring 配置文件中启用它。例如:

<beans>
<context:annotation-config/>
<!-- bean definitions go here -->
</beans>
  • 基于 Java API 配置

Spring 的 Java 配置是通过使用 @Bean 和 @Configuration 来实现。

  1. @Bean 注解扮演与 <bean /> 元素相同的角色。
  2. @Configuration 类允许通过简单地调用同一个类中的其他 @Bean 方法来定义 bean 间依赖关系。

例如:

@Configuration
public class StudentConfig {
    @Bean
    public StudentBean myStudent() {
        return new StudentBean();
    }
}

【中等】Spring Bean 支持哪些作用域?🌟🌟

作用域说明适用场景配置
singleton默认,每个容器一个实例无状态 Bean:Service, DAO, 工具类@Scope("singleton") (默认)
prototype每次请求创建一个新实例有状态 Bean:需要隔离的对象@Scope("prototype")
request每个 HTTP 请求一个实例存储请求相关数据@RequestScope
session每个 HTTP Session 一个实例存储用户会话信息:购物车、用户身份@SessionScope
application每个 Web 应用一个实例存储全局应用级数据@ApplicationScope

【困难】Spring Bean 的生命周期是怎样的?🌟🌟🌟

Spring Bean 容器的生命周期如下:

  • 实例化:Spring 容器根据配置文件或注解实例化 Bean 对象。
  • 属性注入:Spring 将依赖(通过构造器、setter 方法或字段注入)注入到 Bean 实例中。
  • 初始化前的扩展机制:如果 Bean 实现了 BeanNameAware 等 aware 接口,则执行 aware 注入。
  • 初始化前(BeanPostProcessor):在 Bean 初始化之前,可以通过 BeanPostProcessor 接口对 Bean 进行一些额外的处理。
  • 初始化:调用 InitializingBean 接口的 afterPropertiesSet () 方法或通过 init-method 属性指定的初始化方法。
  • 初始化后(BeanPostProcessor):在 Bean 初始化后,可以通过 BeanPostProcessor 进行进一步的处理。
  • 使用 Bean:Bean 已经初始化完成,可以被容器中的其他 Bean 使用。
  • 销毁:当容器关闭时,Spring 调用 DisposableBean 接口的 destroy () 方法或通过 destroy-method 属性指定的销毁方法。

【中等】什么是自动装配?

Spring 容器能够自动装配 bean。也就是说,可以通过检查 BeanFactory 的内容让 Spring 自动解析 bean 的协作者。

自动装配的不同模式:

  • no - 这是默认设置,表示没有自动装配。应使用显式 bean 引用进行装配。
  • byName - 它根据 bean 的名称注入对象依赖项。它匹配并装配其属性与 XML 文件中由相同名称定义的 bean。
  • byType - 它根据类型注入对象依赖项。如果属性的类型与 XML 文件中的一个 bean 名称匹配,则匹配并装配属性。
  • 构造器 - 它通过调用类的构造器来注入依赖项。它有大量的参数。
  • autodetect - 首先容器尝试通过构造器使用 autowire 装配,如果不能,则尝试通过 byType 自动装配。

自动装配的局限:

  • 覆盖的可能性 - 您始终可以使用 <constructor-arg><property> 设置指定依赖项,这将覆盖自动装配。
  • 基本元数据类型 - 简单属性(如原数据类型,字符串和类)无法自动装配。
  • 令人困惑的性质 - 总是喜欢使用明确的装配,因为自动装配不太精确。

IoC

【简单】什么是 IoC?什么是依赖注入?什么是 Spring IoC?🌟🌟🌟

控制反转(IoC)是一种设计思想:将对象的创建控制权从程序内部“反转”给外部容器,目的是解耦

依赖注入(DI)是实现 IoC 的具体技术:由容器动态地将依赖关系注入到对象中(通过构造器或 Setter)。

Spring IoC 是 Spring 对 IoC/DI 的实现。Spring 的 IoC 容器负责管理所有对象(称为 Bean),包括创建、组装和管理其生命周期。

一言以蔽之:遵循 IoC 思想,通过 DI 技术实现,而 Spring IoC 就是最主流的实现容器。

【简单】依赖注入有哪些实现方式?

依赖注入有如下方式:

依赖注入方式配置元数据举例
Setter 方法注入<proeprty name="user" ref="userBean"/>
构造器注入<constructor-arg name="user" ref="userBean" />
字段注入@Autowired User user;
方法注入@Autowired public void user(User user) { ... }
接口回调注入class MyBean implements BeanFactoryAware { ... }

【简单】BeanFactory 和 ApplicationContext 有什么区别?🌟

在 Spring 中,有两种 IoC 容器:BeanFactoryApplicationContext

  • BeanFactoryBeanFactory 是 Spring 基础 IoC 容器BeanFactory 提供了 Spring 容器的配置框架和基本功能。
  • ApplicationContextApplicationContext 是具备应用特性的 BeanFactory 的子接口。它还扩展了其他一些接口,以支持更丰富的功能,如:国际化、访问资源、事件机制、更方便的支持 AOP、在 web 应用中指定应用层上下文等。

实际开发中,更推荐使用 ApplicationContext 作为 IoC 容器,因为它的功能远多于 BeanFactory

【简单】BeanFactory 和 FactoryBean 有什么区别?🌟

BeanFactory 是 Spring 基础 IoC 容器

FactoryBean 是创建 Bean 的一种方式,帮助实现复杂的初始化逻辑。

【困难】Spring 如何解决循环依赖?🌟🌟🌟

Spring 采用三级缓存来解决循环依赖,其关键是:提前暴露未完全创建完毕的 Bean

三级缓存:

  • 一级缓存(成品,singletonObjects:存放完全初始化的单例 Bean。
  • 二级缓存(半成品,earlySingletonObjects:存放从工厂中取出的早期引用,用于提前暴露对象,避免循环依赖问题。
  • 三级缓存(工厂,singletonFactories最关键的一步。存放 Bean 的工厂(ObjectFactory),用于提前暴露一个尚未初始化完成的 Bean 的引用(特别是为了支持 AOP 代理对象的创建)。

解决步骤:

  1. 实例化 & 暴露工厂:实例化 Bean A 后,立即将其工厂放入三级缓存提前暴露引用
  2. 填充属性时循环引用:为 A 注入 B 时,触发创建 B。B 在注入 A 时,能从三级缓存的工厂中获取到 A 的早期引用。
  3. 升级缓存 & 完成注入:将获取到的早期引用 A 放入二级缓存,并注入给 B,从而让 B 和 A 都能顺利完成创建。

【困难】Spring 解决循环依赖为什么一定要用三级缓存?🌟🌟

选择三级缓存而非二级缓存,主要出于** AOP 代理**的考虑,而非单纯解决循环依赖。

  • 二级缓存问题:如果使用二级缓存,必须在 Bean 实例化后立即创建代理。这违背了 Spring 在 Bean 初始化完成后才创建代理的设计原则,且可能导致注入的是原始对象而非最终代理对象。
  • 三级缓存优势:三级缓存存储的是一个能生产最终代理对象的工厂。当发生循环依赖时,由工厂动态决定返回原始对象还是代理对象,从而确保注入的总是最终版本的对象,同时遵守了代理的创建时机原则。

一言以蔽之:三级缓存通过一个延迟处理的工厂,确保了在循环依赖中注入的也是最终的代理对象,维护了 AOP 与 IOC 的正确行为

AOP

【简单】什么是 AOP?🌟🌟🌟

**AOP(面向切面编程)**是一种编程思想,将与核心业务无关的公共功能(如日志、事务)从业务代码中剥离出来,集中管理和复用,作为 OOP(面向对象编程)的有效补充。

为什么需要 AOP?

解决 “横切关注点” 问题,即那些分散在各个模块中的重复性代码(如日志、安全、事务)。目标是:解耦、避免代码重复、提升可维护性。换句话说,AOP 能在不修改原有业务代码的情况下,给程序动态、统一地添加功能

AOP 核心概念

  • 切面(Aspect)“做什么”。封装公共功能的模块(如日志模块)。
  • 通知(Advice)“何时做”。定义切面工作的具体时机(如方法调用前、后)。
    • 前置通知(Before):在方法执行之前执行的操作。
    • 后置通知(After):在方法执行之后执行的操作。
    • 环绕通知(Around):在方法执行前后都可以执行的操作,可以控制方法是否执行。
    • 异常通知(AfterThrowing):在方法抛出异常后执行的操作。
    • 返回通知(AfterReturning):在方法成功返回后执行的操作。
  • 切点(Pointcut)“在哪做”。通过表达式匹配需要切入的具体方法。
  • 连接点(JoinPoint)“可以做的点”。程序执行中的节点(如方法调用),是切点的具体实例。
img
img

【中等】Spring AOP 有哪些实现方式?🌟🌟🌟

Spring AOP 基于动态代理,主要分为两种实现方式:

  • JDK 动态代理

    • 条件:代理实现了接口的类。
    • 原理:通过反射创建实现了相同接口的代理对象。
    • 限制:只能代理接口中定义的方法
  • CGLIB 代理

    • 条件:代理未实现接口的类。
    • 原理:通过字节码技术生成目标类的子类作为代理对象。
    • 限制:无法代理 finalfinal/static 方法

选择策略

  • 默认行为:有接口用 JDK,无接口用 CGLIB
  • 强制配置:可通过设置 proxy-target-class=true 强制所有情况都使用 CGLIB

一句话总结:Spring AOP 在运行时通过 JDK 代理(基于接口)CGLIB 代理(基于继承) 动态生成代理对象,从而将切面逻辑织入目标方法。

注解

你用过哪些重要的 Spring 注解?

  • @Controller - 用于 Spring MVC 项目中的控制器类。
  • @Service - 用于服务类。
  • @RequestMapping - 用于在控制器处理程序方法中配置 URI 映射。
  • @ResponseBody - 用于发送 Object 作为响应,通常用于发送 XML 或 JSON 数据作为响应。
  • @PathVariable - 用于将动态值从 URI 映射到处理程序方法参数。
  • @Autowired - 用于在 spring bean 中自动装配依赖项。
  • @Qualifier - 使用 @Autowired 注解,以避免在存在多个 bean 类型实例时出现混淆。
  • @Scope - 用于配置 spring bean 的范围。
  • @Configuration@ComponentScan@Bean - 用于基于 java 的配置。
  • @Aspect@Before@After@Around@Pointcut - 用于切面编程(AOP)。

如何在 spring 中启动注解装配?

默认情况下,Spring 容器中未打开注解装配。因此,要使用基于注解装配,我们必须通过配置<context:annotation-config /> 元素在 Spring 配置文件中启用它。

@Component, @Controller, @Repository, @Service 有何区别?

  • @Component:这将 java 类标记为 bean。它是任何 Spring 管理组件的通用构造型。spring 的组件扫描机制现在可以将其拾取并将其拉入应用程序环境中。
  • @Controller:这将一个类标记为 Spring Web MVC 控制器。标有它的 Bean 会自动导入到 IoC 容器中。
  • @Service:此注解是组件注解的特化。它不会对 @Component 注解提供任何其他行为。您可以在服务层类中使用 @Service 而不是 @Component,因为它以更好的方式指定了意图。
  • @Repository:这个注解是具有类似用途和功能的 @Component 注解的特化。它为 DAO 提供了额外的好处。它将 DAO 导入 IoC 容器,并使未经检查的异常有资格转换为 Spring DataAccessException。

@Required 注解有什么用?

@Required 应用于 bean 属性 setter 方法。此注解仅指示必须在配置时使用 bean 定义中的显式属性值或使用自动装配填充受影响的 bean 属性。如果尚未填充受影响的 bean 属性,则容器将抛出 BeanInitializationException。

示例:

public class Employee {
    private String name;
    @Required
    public void setName(String name){
        this.name=name;
    }
    public string getName(){
        return name;
    }
}

@Autowired 注解有什么用?

@Autowired 可以更准确地控制应该在何处以及如何进行自动装配。此注解用于在 setter 方法,构造器,具有任意名称或多个参数的属性或方法上自动装配 bean。默认情况下,它是类型驱动的注入。

public class Employee {
    private String name;
    @Autowired
    public void setName(String name) {
        this.name=name;
    }
    public string getName(){
        return name;
    }
}

@Qualifier 注解有什么用?

当您创建多个相同类型的 bean 并希望仅使用属性装配其中一个 bean 时,您可以使用@Qualifier 注解和 @Autowired 通过指定应该装配哪个确切的 bean 来消除歧义。

例如,这里我们分别有两个类,Employee 和 EmpAccount。在 EmpAccount 中,使用@Qualifier 指定了必须装配 id 为 emp1 的 bean。

Employee.java

public class Employee {
    private String name;
    @Autowired
    public void setName(String name) {
        this.name=name;
    }
    public string getName() {
        return name;
    }
}

EmpAccount.java

public class EmpAccount {
    private Employee emp;

    @Autowired
    @Qualifier(emp1)
    public void showName() {
        System.out.println(Employee name :+emp.getName);
    }
}

@RequestMapping 注解有什么用?

@RequestMapping 注解用于将特定 HTTP 请求方法映射到将处理相应请求的控制器中的特定类/方法。此注解可应用于两个级别:

  • 类级别:映射请求的 URL
  • 方法级别:映射 URL 以及 HTTP 请求方法

数据篇

【中等】Spring DAO 有哪些异常?

img
img

【中等】什么是 Spring 的事务管理?

Spring 支持声明式、编程式、注解式定义事务。

Spring 事务定义的属性有:

  • 隔离级别DEFAULT(使用数据库默认),READ_COMMITTEDREPEATABLE_READ
  • 传播行为REQUIRED(默认),REQUIRES_NEWNESTEDSUPPORTS
  • 回滚规则:指定哪些异常触发回滚
  • 是否只读
  • 事务超时

【中等】Spring 事务支持哪些传播行为?🌟

传播行为当前有事务当前无事务
REQUIRED (默认)Propagation.REQUIRED加入当前事务新建一个事务
SUPPORTSPropagation.SUPPORTS加入当前事务非事务运行
MANDATORYPropagation.MANDATORY加入当前事务抛出异常
REQUIRES_NEWPropagation.REQUIRES_NEW挂起当前并新建新建一个事务
NOT_SUPPORTEDPropagation.NOT_SUPPORTED挂起当前并非事务运行非事务运行
NEVERPropagation.NEVER抛出异常非事务运行
NESTEDPropagation.NESTED嵌套事务中执行新建一个事务

MVC

【困难】Spring MVC 是如何工作的?🌟🌟🌟

Spring MVC 的核心是 DispatcherServlet,它充当了前端控制器(Front Controller)的模式,是所有请求的统一入口,负责协调各个组件完成请求处理

img
img

请求流程

  1. 用户请求:用户通过浏览器发送 HTTP 请求到服务器。
  2. DispatcherServlet 接收请求:作为前端控制器,DispatcherServlet 拦截所有请求。
  3. HandlerMapping 映射处理器:DispatcherServlet 调用 HandlerMapping,根据请求的 URL 找到对应的处理器(Controller)。
  4. HandlerAdapter 调用处理器:DispatcherServlet 通过 HandlerAdapter 调用具体的处理器方法,执行业务逻辑。
  5. 处理器返回 ModelAndView:处理器处理完请求后,返回包含模型数据和视图信息的 ModelAndView 对象。
  6. ViewResolver 解析视图:DispatcherServlet 使用 ViewResolver 将逻辑视图名解析为具体的视图实现(如 JSP)。
  7. 渲染视图:视图组件将模型数据填充到视图中,生成最终的响应内容。
  8. 返回响应:DispatcherServlet 将渲染后的视图返回给客户端,完成请求-响应的整个过程。

核心组件

  • DispatcherServlet:作为前端控制器,负责接收请求并协调其他组件的工作。
  • HandlerMapping:根据请求的 URL,将请求映射到对应的处理器。
  • HandlerAdapter:调用处理器方法,并处理返回结果。
  • Controller:处理具体的业务逻辑,生成模型和视图信息。
  • ModelAndView:包含处理结果和视图信息的对象。
  • ViewResolver:将逻辑视图名解析为实际的视图实现。
  • View:负责将模型数据渲染成最终的响应内容。

配置与扩展

  • 注解支持:使用 @Controller@RequestMapping 等注解简化开发。
  • 拦截器(Interceptor):在请求处理前后执行额外的逻辑,如权限检查、日志记录等。
  • 数据绑定与验证:提供数据绑定和验证机制,方便处理表单数据。
    通过以上流程和组件,Spring MVC 实现了请求的分发、处理、视图渲染等功能,使开发者能够高效地开发 Web 应用程序。

资料

评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.15.7