Spring 面试题

1、什么是 Spring

Spring 是一个轻量级的 IOC 和 AOP 容器框架。是为 Java 应用程序提供基础性服务的一套框架,目的是用于简化企业应用程序的开发,它使得开发者只需要关心业务需求。常见的配置方式有三种:基于 XML 的配置、基于注解的配置、基于 Java 的配置。

主要由以下几个模块组成:

  • Spring Core:核心类库,提供 IOC 服务
  • Spring Context:提供框架式的 Bean 访问方式,以及企业级功能(JNDI、定时任务等)
  • Spring AOP:提供 AOP 服务
  • Spring DAO:对 JDBC 的抽象,简化了数据访问异常的处理
  • Spring ORM:对现有的 ORM 框架的支持
  • Spring Web:提供了基本的面向 Web 的综合特性,例如多方文件上传
  • Spring MVC:提供了面向 Web 应用的 Model-View-Controller 实现

2、你们项目中为什么使用 Spring 框架

这么问的话,就直接说 Spring 框架的好处就可以了。比如说 Spring 有以下特点:

  • 轻量:Spring 是轻量的,基本的版本大约2MB。
  • 控制反转:Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。
  • 面向切面的编程(AOP):Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。
  • 容器:Spring 包含并管理应用中对象的生命周期和配置。
  • MVC框架:Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品。
  • 事务管理:Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)。
  • 异常处理:Spring 提供方便的API把具体技术相关的异常(比如由JDBC,Hibernate or JDO抛出的)转化为一致的unchecked 异常。

Spring 是一个轻量级的 IOC 和 AOP 容器框架。轻量,体积小。IOC 控制反转可以减少程序耦合。AOP 可以把应用业务逻辑和系统服务分离开。容器可以管理应用中对象的生命周期和配置。其中的 MVC 框架是一个优秀的 Web 开发框架。提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务。提供方便的 API 把具体技术相关的异常转化为一致的 unchecked 异常

3、Autowired 和 Resource 关键字的区别

相同点:都是用来实现依赖注入的注解

不同点:

  1. 来源不同:@Autowired 是 Spring 定义的注解,而 @Resource 是 Java 定义的注解

  2. 依赖注入的支持不同:

    @Autowired 支持属性注入、Setter 注入、构造方法注入

    @Resource 只支持属性注入和 Setter 注入

  3. 支持的参数不同:

    @Autowired 只支持一个 required 的参数

    @Resource 支持 name 和 type 等7 个参数

  4. 依赖查找顺序不同:

    @Autowired 默认情况下它要求依赖对象必须存在,先根据类型(byType)查找,如果找不到 bean,则装配失败;如果找到唯一的bean,则执行装配;如果找到多个 bean,根据 @Autowired 标记位置成员变量的变量名作为 bean 的 id 进行查找,找到则装配,找不到装配失败;如果允许依赖对象为 null 值,可以设置它的 required 属性为 false。

    @Resource 如果同时指定了 name 和 type,则从 Spring 上下文中找到唯一匹配的 bean 进行装配,找不到则抛出异常;如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常;如果指定了 type,则从上下文中找到类似匹配的唯一 bean 进行装配,找不到或是找到多个,都会抛出异常;如果既没有指定 name,又没有指定 type,则自动按照 byName 方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。

4、依赖注入的方式有几种,各是什么

Java 中依赖注入的方式有三种,分别是构造器注入、Setter 方法注入和接口注入 。

  • 构造器注入:通过构造函数将依赖项传递给对象

    优点是可以在对象创建时就完成依赖注入,保证了对象的完整性

    缺点是如果依赖项过多,会导致构造函数过长,不易于维护

  • Setter 方法注入:通过对象的 Setter 方法将依赖项传递给对象

    优点是可以在运行时动态地完成依赖注入,提高了程序的灵活性

    缺点是需要为每个属性编写 Setter 方法,代码量较大

  • 接口注入:通过实现一个特定的接口来注入依赖项

    优点是可以通过接口控制依赖项的类型,提高了代码的安全性

    缺点是需要为每个依赖项编写实现类,代码量较大

5、说说你对 Spring MVC 的理解

Spring MVC 是 Spring 框架中的一个模块,专门用来做 Web 开发使用的。它是一个典型的轻量级 MVC 框架,在整个 MVC 架构中充当控制器框架,相对于之前的 struts2 框架,Spring MVC 运行更快,其注解式开发更高效灵活。可以和 Spring 框架无缝整合。

MVC 模式是一种软件架构模式,其目标是将软件的用户界面(即前台页面)和业务逻辑分离,使代码具有更高的可扩展性、可复用性、可维护性以及灵活性。 MVC 模式将应用程序划分成模型(Model)、视图(View)、控制器(Controller)等三层,其中模型代表数据层,视图代表显示层,控制器代表控制层。

工作原理:

1、用户发送请求至前端控制器 DispatcherServlet。

2、DispatcherServlet 收到请求调用 HandlerMapping 处理器映射器。

3、处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。

4、DispatcherServlet 调用 HandlerAdapter 处理器适配器。

5、HandlerAdapte 经过适配调用具体的 Controller 处理器(Controller,也叫后端控制器)。

6、Controller 执行完成返回 ModelAndView。

7、HandlerAdapter 将 Controller 执行结果 ModelAndView 返回给 DispatcherServlet。

8、DispatcherServlet 将 ModelAndView 传给 ViewReslover 视图解析器。

9、ViewReslover 解析后返回具体 View。

10、DispatcherServlet 根据 View 进行渲染视图(即将模型数据填充至视图中)。

11、DispatcherServlet 响应用户。

6、Spring MVC 常用的注解有哪些

  1. @Controller:控制层注解,将类标识为控制器,用于接收用户请求
  2. @ResponseBody:将返回值转化为 JSON 格式的数据
  3. @RestController:@Controller和@ResponseBody的复合注解
  4. @RequestMapping:映射请求到特定的处理方法上
  5. @RequestBody:注解实现接收 http 请求的 json 数据,将 json 转换为 java 对象
  6. @PathVariable:将 URL 中的占位符替换为实际的值。
  7. @RequestParam:从请求中获取参数值
  8. @ModelAttribute:将请求参数绑定到模型对象上
  9. @RequestHeader:获取请求头信息
  10. @CookieValue:获取 cookie 值

7、谈谈你对 Spring 的 AOP 理解

AOP 面向切面编程,能够将业务逻辑和系统服务分离开,减少系统的重复代码,降低模块间的耦合度,提高代码的可扩展性和可维护性。

Spring AOP 是基于动态代理的,如果要代理的对象实现了某个接口,那么 Spring AOP 就会使用 JDK 动态代理去创建代理对象;而对于没有实现接口的对象,就无法使用 JDK 动态代理,转而使用 CGlib 动态代理生成一个被代理对象的子类来作为代理。

8、Spring AOP 和 AspectJ AOP 有什么区别?

Spring AOP 是运行时增强,而 AspectJ 是编译时增强。Spring AOP 基于代理(Proxying),而 AspectJ 基于字节码操作(Bytecode Manipulation)。

Spring AOP 已经集成了 AspectJ ,AspectJ 应该算得上是 Java 生态系统中最完整的 AOP 框架了。AspectJ 相比于 Spring AOP 功能更加强大,但是 Spring AOP 相对来说更简单。

如果我们的切面比较少,那么两者性能差异不大。但是,当切面太多的话,最好选择 AspectJ,它比 Spring AOP 快很多。

9、在 Spring AOP 中,关注点和横切关注的区别是什么?

关注点:表示具体的业务逻辑或功能模块

横切关注:表示多个关注点共同使用的功能

在Spring AOP中,关注点(Concern)和横切关注(Cross-cutting Concern)是两个重要的概念。关注点是指程序中的某个功能模块或任务,例如日志记录、事务管理、异常处理等,这些通常与特定的类或方法相关联。而横切关注则是指会影响多个模块的公共功能或任务,如日志、安全和数据传输,几乎应用的每个模块都需要的功能。其核心区别在于,关注点表示业务逻辑或功能的不同部分,是应用程序中的独立部分;而横切关注则是与多个关注点相关的功能,这些功能在整个应用程序中被共享和重复地使用。Spring AOP的目的是将跨越多个关注点的横切关注进行解耦和管理,通过在源代码中定义切点,并在切点上应用通知来实现这一目标。

10、什么是通知呢?有哪些类型呢?

通知是个在方法执行前或执行后要做的动作,实际上是程序执行时要通过 Spring AOP 框架触发的代码段。

Spring切面可以应用五种类型的通知:

  1. 前置通知(Before):在一个方法执行前被调用。
  2. 后置通知(After):在方法执行之后调用的通知,无论方法执行是否成功。
  3. 返回通知(AfterReturning):仅当方法成功完成后执行的通知。
  4. 异常通知(AfterThrowing):在方法抛出异常退出时执行的通知。
  5. 环绕通知(Around):在方法执行之前和之后调用的通知。

11、说说你对 Spring 的 IOC 是怎么理解的?

IOC,全称Inversion of Control,即控制反转,不是具体的技术,而是一种设计思想。传统的创建对象的方法是直接通过new关键字,而Spring 则是通过 IOC 容器来创建对象,也就是说我们将创建对象的控制权从程序员手中释放出来,转交给了Spring框架。

DI 依赖注入是 IOC 的具体实现方式,使用 IOC 的目的主要是为了降低程序代码之间的耦合度。

12、解释一下 Spring Bean 的生命周期

Spring Bean 的生命周期:

  1. 首先实例化阶段,通过反射创建出对象。
  2. 接着是属性赋值阶段,将 Bean 的属性设置为配置文件中指定的值。
  3. 然后是初始化阶段,用户可以在此阶段自定义一些行为。
  4. 最后是销毁阶段,进行 Bean 对象的销毁操作。

13、解释 Spring 支持的几种 Bean 的作用域

  1. singleton :容器中只有一个Bean的实例

  2. prototype:容器中有多个Bean的实例

  3. request:每次 http 请求都会创建一个 Bean 的实例

  4. session:首次 http 请求创建一个 Bean 实例,作用域是浏览器首次访问直至浏览器关闭

  5. global-session:全局作用域,所有的会话共享同一个 Bean 实例

14、Spring 基于 XML 注入 Bean 的几种方式?

  1. Set方法注入
  2. 构造器注入:①通过index设置参数的位置;②通过type设置参数类型
  3. 静态工厂注入
  4. 实例工厂注入

15、Spring 框架中都用到了哪些设计模式?

  1. 简单工厂模式:BeanFactory、通过传入一个唯一标识来获取Bean对象。
  2. 工厂模式:FactoryBean
  3. 单例模式:scope=“singleton”
  4. 原型模式:scope=“prototype”
  5. 代理模式:基于 JDK 和 CGlib 的动态代理
  6. 适配器模式:MVC 中的 Adapter
  7. 模板方法模式:JdbcTemplate

这是一道相对有难度的题目,你不仅要回设计模式,还要知道每个设计模式在Spring中是如何使用的。

简单工厂模式:Spring 中的 BeanFactory 就是简单工厂模式的体现。根据传入一个唯一的标识来获得 Bean 对象,但是在传入参数后创建还是传入参数前创建,要根据具体情况来定。

工厂模式:Spring 中的 FactoryBean 就是典型的工厂方法模式,实现了 FactoryBean 接口的 bean是一类叫做 factory 的 bean。其特点是,spring 在使用 getBean() 调用获得该 bean 时,会自动调用该 bean 的 getObject() 方法,所以返回的不是 factory 这个 bean,而是这个 bean.getOjbect()方法的返回值。

单例模式:在 spring 中用到的单例模式有: scope=“singleton” ,注册式单例模式,bean 存放于Map 中。bean name 当做 key,bean 当做 value。

原型模式:在 spring 中用到的原型模式有: scope=“prototype” ,每次获取的是通过克隆生成的新实例,对其进行修改时对原有实例对象不造成任何影响。

迭代器模式:在 Spring 中有个 CompositeIterator 实现了 Iterator,Iterable 接口和 Iterator 接口,这两个都是迭代相关的接口。可以这么认为,实现了 Iterable 接口,则表示某个对象是可被迭代的。Iterator 接口相当于是一个迭代器,实现了 Iterator 接口,等于具体定义了这个可被迭代的对象时如何进行迭代的。

代理模式:Spring 中经典的 AOP,就是使用动态代理实现的,分 JDK 和 CGlib 动态代理。

适配器模式:Spring 中的 AOP 中 AdvisorAdapter 类,它有三个实现:MethodBeforAdviceAdapter、AfterReturnningAdviceAdapter、ThrowsAdviceAdapter。Spring会根据不同的 AOP 配置来使用对应的 Advice,与策略模式不同的是,一个方法可以同时拥有多个Advice。Spring 存在很多以 Adapter 结尾的,大多数都是适配器模式。

观察者模式:Spring 中的 Event 和 Listener。spring 事件:ApplicationEvent,该抽象类继承了EventObject 类,JDK 建议所有的事件都应该继承自 EventObject。spring 事件监听器:ApplicationListener,该接口继承了 EventListener 接口,JDK 建议所有的事件监听器都应该继承EventListener。

模板模式:Spring 中的 org.springframework.jdbc.core.JdbcTemplate 就是非常经典的模板模式的应用,里面的 execute 方法,把整个算法步骤都定义好了。

责任链模式:DispatcherServlet 中的 doDispatch() 方法中获取与请求匹配的处理器HandlerExecutionChain,this.getHandler() 方法的处理使用到了责任链模式。

注意:这里只是列举了部分设计模式,其实里面用到了还有享元模式、建造者模式等。可选择性的回答,主要是怕你回答了迭代器模式,然后继续问你,结果你一问三不知,那就尴了尬了。

16、说说 Spring 中 ApplicationContext 和 BeanFactory 的区别

  1. 包目录不同:一个来源 bean 包,一个来源 context 包
  2. 国际化:BeanFactory 没有实现 MessageResource 接口,不支持国际化,ApplicationContext 支持国际化
  3. 延迟加载:BeanFactroy 是通过延迟来注入 Bean 的
  4. 强大的事件机制:ApplicationContext 具有强大的事件机制,通过观察者设计模式来实现
  5. 对web应用的支持:BeanFactory 通常以编程的方式进行创建、ApplicationContext 以声明式创建,如ContextLoader
  6. ApplicationContext 继承了 BeanFactory ,BeanFactory 是 Spring 比较原始的 Bean,ApplicationContext 是对 BeanFactory 很好的扩展

17、Spring 框架中的单例 Bean 是线程安全的么

Spring 框架中的单例 Bean 默认情况下并不是线程安全的。这是因为 Spring 容器中的 Bean 本身并不具备线程安全的特性,容器并没有提供 Bean 的线程安全策略。实际上,在多线程环境下,当多个线程同时访问同一个单例 Bean 时,可能会引发线程安全问题。

大部分时候,我们使用的 Bean 是无状态的,即使多个线程调用同一个实例的方法,由于方法内部不会保存数据,因此是线程安全的。如果 Bean 是有状态的,我们就需要保证线程安全。最简单的办法就是将 Bean 的作用域,从 singleton 改为 prototype,这样每次请求都会创建新的 Bean。

18、Spring 是怎么解决循环依赖的?

假设 A 依赖 B,B 依赖 C,C 依赖 A:

  1. 首先 A 完成初始化并将自己提前曝光出来(通过 ObjectFactory 将自己提前曝光),在初始化的时候,发现自己依赖 B,尝试 get(B),发现 B 还没有被创建出来
  2. 然后 B 就开始初始化,在 B 初始化的时候,同样发现自己依赖 C,尝试 get©,发现 C 还没有被创建出来
  3. 这个时候 C 又开始初始化,但是在初始化的过程中发现自己依赖 A,于是尝试 get(A)。这个时候由于 A 已经添加至缓存中(一般都是添加至三级缓存 singletonFactories),通过 ObjectFactory 提前曝光,所以可以通过 ObjectFactory#getObject() 方法来拿到 A 。C 拿到 A 后顺利完成初始化,然后将自己添加到一级缓存中
  4. 回到 B,B 也可以拿到 C ,完成初始化,A 可以顺利拿到 B 完成初始化。到这里整个链路就已经完成了初始化过程了

19、说说事务的传播级别

  1. REQUIRED(默认):如果上下文中存在事务则加入当前事务,如果不存在事务则新建事务执行。
  2. SUPPORTS:支持当前事务,如果当前没有事务就以非事务方式执行。
  3. MANDATORY:必须在事务中执行,如果当前没有事务就抛出异常。
  4. REQUIRES_NEW:创建一个新的事务,如果当前存在事务则把当前事务挂起。
  5. NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务则把当前事务挂起。
  6. NEVER:以非事务方式执行,如果当前存在事务则抛出异常。
  7. NESTED:如果调用方法A,会开启一个事务,在方法A内部调用方法B,由于方法A已经存在开启尚未提交的事务,方法B的传播级别为NESTED,会加入这个事务当中。

20、Spring 事务实现方式

编程式事务管理:通过编程的方式管理事务,比较灵活,但很难维护。

声明式事务管理:将事务管理和业务代码分离。只需要通过注解或者 XML 配置管理事务。

21、Spring 框架的事务管理有哪些优点

  1. 为不同的事务 API(如JTA, JDBC, Hibernate, JPA, 和JDO)提供了统一的编程模型
  2. 为编程式事务管理提供了一个简单的 API 而非一系列复杂的事务 API(如JTA)
  3. 支持声明式事务管理
  4. 可以和 Spring 的多种数据访问技术很好的融合

22、事务三要素是什么?

  1. 数据源:表示具体的事务性资源,是事务的真正处理者,如 MySQL 等。
  2. 事务管理器:像一个大管家,从整体上管理事务的处理过程,如打开、提交、回滚等。
  3. 事务应用和属性配置:像一个标识符,表明哪些方法要参与事务,如何参与事务,以及一些相关属性如隔离级别、超时时间等。

23、事务注解的本质是什么?

@Transactional 表明该方法要参与事务并配置相关属性来定制事务的参与方式和运行行为

声明式事务主要是得益于 Spring AOP。使用一个事务拦截器,在方法调用的前后/周围进行事务性增强(advice),来驱动事务完成。

@Transactional注解既可以标注在类上,也可以标注在方法上。当在类上时,默认应用到类里的所有方法。如果此时方法上也标注了,则方法上的优先级高。 另外注意方法一定要是public的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值