面试题首页 > Spring面试题

Spring高级面试题

001什么是循环依赖?

类与类之间的依赖关系形成了闭环,就会导致循环依赖问题的产生。
比如下图中A类依赖了B类,B类依赖了C类,而最后C类又依赖了A类,这样就形成了循环依赖问题。

002循环依赖类型?

1.通过构造方法进行依赖注入时产生的循环依赖问题。
该情况会报异常,在new对象的时候就会堵塞住了,其实也就是”先有鸡还是先有蛋“的历史难题。
2.通过setter方法进行依赖注入且是在多例模式下产生的循环依赖问题。
该情况会报异常,每一次getBean()时,都会产生一个新的Bean,如此反复下去就会有无穷无尽的Bean产生了,最终就会导致OOM问题的出现。
3.通过setter方法进行依赖注入且是在单例模式下产生的循环依赖问题。
因此在Spring中,前两种都会报异常,只有第(3)种方式的循环依赖问题能被解决。

003如何解决循环依赖?

Spring在单例模式下的setter方法依赖注入引起的循环依赖问题,主要是通过二级缓存和三级缓存来解决的,其中三级缓存是主要功臣。解决的核心原理就是:在对象实例化之后,依赖注入之前,Spring提前暴露的Bean实例的引用在第三级缓存中进行存储。
Spring中有三个缓存,用于存储单例的Bean实例,这三个缓存是彼此互斥的,不会针对同一个Bean的实例同时存储。如果调用getBean,则需要从三个缓存中依次获取指定的Bean实例。 读取顺序依次是一级缓存 ==> 二级缓存 ==> 三级缓存。

004Spring的启动过程?

Spring启动过程是IOC容器的启动过程,本质是创建和初始化bean工厂(BeanFactory).BeanFactory是Spring IOC的核心,Spring使用beanFactory来实例化,配置和管理bean。对于web程序,IOC容器启动过程即是建立上下文的过程,web容器会提供一个全局的servletContext上下文环境。其启动过程主要包含三个类,ContextLoaderListener,ContextLoader和XmlWebApplicationContext。
在web.xml中提供ContextLoaderListener上下文监听器,在web容器启动时,会触发容器初始化事件,ContextLoaderListener会监听到这个事件,从而触发ContextInitialized方法完成上下文初始化,这个方法中调用父类ContextLoader的方法完成上下文初始化。ContextLoader类中主要完成三件事:
1)创建WebApplicationContext;
2)加载对应的Spring配置文件中的bean;(refresh方法,完成bean的加载)
3)将WebApplicationContext放入servletContext中。ContextLoaderListener监听器初始化完之后,开始初始化web.xml中配置的servlet,如DispatcherSevlet
ContextLoaderListener监听器监听的是servletContext,当web容器初始化后,servletContext发生变化时,会触发相应事件。

005Spring对数据库事务管理?

Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。Spring只提供统一事务管理接口,具体实现都是由各数据库自己实现,数据库事务的提交和回滚是通过 redo log 和 undo log实现的。Spring会在事务开始时,根据当前环境中设置的隔离级别,调整数据库隔离级别,由此保持一致。

006Spring事务的种类?

①编程式事务管理使用TransactionTemplate。
②声明式事务管理建立在AOP之上的。其本质是通过AOP功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前启动一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明或通过@Transactional注解的方式,便可以将事务规则应用到业务逻辑中,减少业务代码的污染。唯一不足地方是,最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。

007Spring的事务传播机制

Spring事务的传播机制说的是,当多个事务同时存在的时候,Spring如何处理这些事务的行为。事务传播机制实际上是使用简单的ThreadLocal实现的,所以,如果调用的方法是在新线程调用的,事务传播实际上是会失效的。① PROPAGATION_REQUIRED:(默认传播行为)如果当前没有事务,就创建一个新事务;如果当前存在事务,就加入该事务。
② PROPAGATION_REQUIRES_NEW:无论当前存不存在事务,都创建新事务进行执行。
③ PROPAGATION_SUPPORTS:如果当前存在事务,就加入该事务;如果当前不存在事务,就以非事务执行。‘
④ PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
⑤ PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则按REQUIRED属性执行。
⑥ PROPAGATION_MANDATORY:如果当前存在事务,就加入该事务;如果当前不存在事务,就抛出异常。
⑦ PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。

008Spring事务的隔离级别?

① ISOLATION_DEFAULT:这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。
② ISOLATION_READ_UNCOMMITTED:读未提交,允许事务在执行过程中,读取其他事务未提交的数据。
③ ISOLATION_READ_COMMITTED:读已提交,允许事务在执行过程中,读取其他事务已经提交的数据。
④ ISOLATION_REPEATABLE_READ:可重复读,在同一个事务内,任意时刻的查询结果都是一致的。
⑤ ISOLATION_SERIALIZABLE:所有事务逐个依次执行。

009什么时候@Transactional失效?

1. @Transactional配置的方法非public权限修饰(例如private的就别加了);
2. @Transactional所在类非Spring容器管理的bean(例如一个Util就别加了,都没注入容器,你叫Spring怎么用他的AOP帮你管理事务?);
3. @Transactional所在类中,注解修饰的方法被类内部方法调用(例如同一个class类中,方法A调用方法B,只在方法B加了@Transactional注解,那就失效了);
4. 业务代码抛出异常类型非RuntimeException,事务失效;
5. 业务代码中存在异常时,使用try…catch…语句块捕获,而catch语句块没有throw new RuntimeExecption异常(只有该异常或者他的父异常例如Exception可以回滚);
6. 注解@Transactional中Propagation属性值设置错误(例如Propagation.NOT_SUPPORTED,一般不会这么设置)
7. mysql关系型数据库,且存储引擎是MyISAM而非InnoDB,则事务会不起作用。

010Spring 什么情况下进行事务回滚?

在java中异常的基类为Throwable,Error和Exception继承Throwable。Exception中RuntimeException及其子类成为未检查异常(unchecked),其它Exception成为已检查异常(checked)。
Spring的事务管理默认是针对unchecked exception回滚,也就是默认对Error异常和RuntimeException异常以及其子类进行事务回滚,且必须抛出异常,若使用try-catch对其异常捕获则不会进行回滚!(Error异常和RuntimeException异常抛出时不需要方法调用throws或try-catch语句);
checked异常,checked异常必须由try-catch语句包含或者由方法throws抛出,且事务默认对checked异常不进行回滚。

目录

返回顶部