Spring部分常见面试题
1、Spring框架的基本理解(重点)
Spring 框架是一款轻量级的开发框架,核心思想是IOC(控制反转)和AOP(面向切面编程)
为Java 应用程序开发提供组件管理服,用于组件之间的解耦,以及简化第三方JavaEE中间件技术的
使用(JMS、任务调度、缓存、ORM框架),是一个基础架构型的开发框架;
2、Spring 框架由哪些模块组成?
Core: 核心模块
包括:IoC Container (loc容器),Events(事件通知机制),Resources(资源加载机制),
i18n(国际化),Validation(数据校验),Data Binding(数据绑定),Type Conversio
n(类型转换),SpEL(Spring表达式),AOP(面向切面编程);
Testing:测试模块
包括:Mock Objects (测试模拟对象),TestContext Framework (测试框架),Spring MVC Test (用于测试 Spring MVC),WebTestClient (用于测试 WebClient、Restful、Webflux 等);
Data Access:数据访问模块
包括:Transactions(事务管理),DAO Support(统一的 Data Access Object DAO 模式
封装),JDBC(Spring 对于 JDBC的操作封装),O/R Mapping(Spring 对于对象关系映射框架
的封装,例如 Hibernate 等框架)等;
Web Servlet:基于Servlet的Web应用开发
包括:Spring MVC (Spring基于MVC 模式设计封装的Web 框架),WebSocket(Sprin
g集成 WebSocket,WebSocket 是一个服务器与客户端双向通信的技术)等;
Integration:企业级系统集成模块(不同系统之间的交互集成)
包括:Remoting(Spring 用于在分布式系统中进行远程服务调用的通讯框架),JMS(Spring
集成各类Java消息中间件、Java消息服务[Java Message Service],例如ActiveMQ等),Java Email(
邮件发送),Tasks Scheduling(任务调度);
3.Spring IOC的理解
IOC(Inversion of Control,中文释义:控制反转)是Spring 框架的核心思想之一,主要
用于解耦。IOC 是指将创建对象的控制权转移给 Spring 框架进行管理。由Spring 框架根据配置
文件或注解等方式,创建bean 对象并管理各个 bean 对象之间的依赖关系。使对象之间形成松散耦
合的关系,实现解耦;
控制:指的是对象创建(实例化、管理)的权力
反转:控制权交给外部环境(Spring框架、IoC 容器)
4. Spring IOC 容器的理解
IOC 通常被理解为 IOC Container 容器,IOC 容器其实就是一个Map,key 是每个bean 对
象的ID,value是bean 对象本身。IOC 容器负责创建bean 对象并管理 bean的生命周期。
并且根据配置好配置文件或注解,管理IOC 容器中的每个bean,以及根据 bean 之间的依赖关
系,完成bean 之间的注入。
· IOC 容器属于 Spring Core 模块,用来创建和管理 Bean,默认使用单例的方式将 bean 存储
在DefaultListableBeanFactory 类的 beanDefinitionMap 中(一个 ConcurrentHashMap类
型的Map集合);
· IOC 容器使用 ConcurrentHashMap 集合存储了 BeanDefinition 对象,该对象封装了 Sprin
g 对一个Bean所有配置信息,包括:类名,属性,构造方法参数,依赖,是否延迟加载,是否是
单例等配置信息;
5、 Spring DI 的理解
DI(Dependecy Inject,中文释义:依赖注入)是对IOC概念的不同角度的描述,是指应用
程序在运行时,每一个bean 对象都依赖 IOC 容器注入当前bean对象所需要的另外一个bean对
象。(例如在MyBatis 整合 Spring时,SqlSessionFactoryBean 依赖 IOC 容器注入一个 D
ataSource 数据源 bean)
6、将一个类声明为Bean的注解有哪些?
@Component
定义通用Bean的注解,可标注任意类为 Bean。如果一个 Bean 不知道属于哪个
层,可以使用 @Component 注解标注。
@Repository
定义数据访问层Bean的注解。
@Service
定义服务层的注解。
@Controller
定义控制层Bean的注解。
7.@Component和@Bean的区别是什么?
@Component 注解作用于类,而@Bean 注解作用于方法。
@Component 通常是通过类路径扫描来实现自动扫描并完成装配Bean到 Spring IOC 容器中。
@Bean 注解通常用于注解某个方法,通过@Bean注解告诉了 Spring IOC 容器,该方法的返回值实例是一个 Bean 。
8.@Autowired和@Resource的区别是什么?
@Autowired 是 Spring 提供的注解,@Resource 是JDK 提供的注解。
@Autowired 默认的注入方式为 byType(按类型自动注入),@Resource 默认注入方式为 byN
ame(按名称自动注入)。
9.Spring框架中的常见注入方式有几种?
Spring IOC 有三种注入方式:构造注入、Setter注入、属性注入:
①构造注入:使用构造方法注入 bean;
②Setter注入:使用Setter方法注入 bean;
③属性注入:使用成员属性注入bean,不推荐。原因:使用私有的成员属性变量,依靠反射实
现,破坏封装,只能依靠IOC 容器实现注入,不严谨;
10.Spring中常见的ApplicationContext实现类有哪些?
①ClassPathXmlApplicationContext:根据项目类路径classpath 下的配置文件加载 bean;
② FileSystemXmlApplicationContext:根据当前磁盘的一个绝对系统文件路径下的配置文件加
载 bean;
③ AnnotationConfigApplicationContext:根据读取到的注解加载 bean;
WebApplicationContext:Web 容器下按照配置文件加载 bean;
11.BeanFactory和ApplicationContext有什么区别?
两者之间的关系:
BeanFactory和ApplicationContext 是Spring的两大核心接口,都可以当
做Spring 的容器
两者区别与不同:
①BeanFactory 是Spring 里面最底层的接口,是IoC 的核心,定义了IoC的基本功能,包含了各种Bean 的定义、加载、实例化,依赖注入和生命周期管理等行为;
②ApplicationContext 接口作为BeanFactory 接口的子接口,包含 BeanFactory 所具备的
功能外,还提供了其它框架功能:继承MessageSource(支持国际化),资源文件访问、可以
同时加载多个配置文件、可以通过监听器管理bean的生命周期;
Bean的创建加载方式:
①BeanFactroy 采用的是延迟加载形式来注入Bean,只有在使用到某个Bean时,才对该 Bea
n 进行加载实例化。这样不能提前发现一些存在的Spring的配置问题。如果Bean的某一个属
性没有注入,BeanFacotry 加载后,直至第一次使用调用getBean()方法才会抛出异常;
②ApplicationContext 是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,
我们就可以发现 Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。Applicat
ionContext 启动后预载入所有的单实例Bean,所以在运行的时候速度比较快,因为它们已经
创建好了。相对于BeanFactory,ApplicationContext 唯一的不足是占用内存空间,当应
用程序配置 Bean 较多时,程序启动较慢。
12.Spring 框架中的Bean的作用域
①singleton:Spring 只会为该bean 对象只会创建唯一实例,Spring 中的bean 默认都是单
例;
②prototype:每次获取bean,Spring 会创建一个新的bean实例;
③request:每一次 HTTP 请求,Spring 会创建一个新的bean实例;
④session:不同的HTTP 会话,Spring 会创建不同的bean实例;
13.Spring 框架中的Bean的线程安全
对于prototype 作用域的Bean,每次都创建一个新对象,也就是线程之间不存在Bean共享,因此
不会有线程安全问题
对于singleton 作用域的Bean,所有的线程都共享一个单例状态的Bean,存在资源竞争,因此
是存在线程安全问题的
解决办法:
对于singleton作用域的单例bean,它的线程安全问题,常见有两种解决办法:
①在 bean 中尽量避免定义可变的成员变量(用于保存数据的成员变量);
②在类中定义一个 ThreadLocal 成员变量,将需要可变的成员变量保存在 ThreadLocal
14.Spring 框架中的Bean生命周期
Spring Bean 的生命周期总体分四个阶段:实例化=> 属性注入=> 初始化=> 销毁
①实例化 Bean:根据配置文件中Bean的定义,利用Java Reflection 反射技术创建 Bea
n 的实例
②注入对象依赖的属性值(或对象)
③处理各种Aware接口:
Spring 会检测该 Bean 是否实现了xxxAware 接口,通过Awar
e 类型的接口,可以让Spring框架为当前 Bean 注入相应的内容。
如果 Bean实现 BeanNameAware 接口,会调用它实现的setBeanName(String beanId)方
法,注入Bean 的名字;
如果 Bean 实现 BeanClassLoaderAware 接口,调用 setBeanClassLoader()方法,注入C
lassLoader 对象的实例;
如果 Bean 实现 BeanFactoryAware 接口,会调用它实现的setBeanFactory()方法,注入
的是Spring 工厂;
如果 Bean 实现 ApplicationContextAware 接口,会调用 setApplicationContext()方法,注入上下文。
④ 执行BeanPostProcessor前置处理:
如果想对 Bean 进行一些自定义的前置处理,那么可以
让 Bean 实现了BeanPostProcessor 接口,将会在该阶段调用postProcessBeforeInitializat j,String s)方法。
⑤执行InitializingBean初始化方法:
如果 Bean 实现了 InitializingBean 接口,执行afeterPropertiesSet()方法
⑥ 执行init-method自定义初始化方法:
如果Bean在Spring 配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。
⑦ 执行BeanPostProcessor后置处理:
如果这个 Bean 实现了BeanPostProcessor接口,将会调用 postProcessAfterInitialization(Object obj,String s)方法,由于这个方法是在 Bean 初始化结束后调用;
以上几个步骤完成后,Bean 已经被正确创建,可以正常使用这个Bean 了。
⑧执行DisposableBean销毁Bean
当Bean 不再需要时,会经过清理阶段,如果Bean 实现
了DisposableBean 这个接口,会调用其实现的destroy()方法执行销毁;
⑨ 执行destroy-method自定义销毁方法:
如果这个Bean的Spring 配置中配置了 destroy-method 属性,会自动调用其配置的自定义销毁方法。
15.Spring 框架如何解决循环依赖?
循环依赖指的是两个或者多个类在他们的创建或初始化过程中直接或间接的相互依赖,形成了闭环。例如A类依赖了B类,B类依赖了C类,而最后C类又依赖了A类,这样就形成了循环依赖问题;
解决方法:三级缓存
1、一级缓存:存已经完全初始化了的Bean实例
2、二级缓存:存早期暴露的Bean实例,未完全初始化。
3、三级缓存:存Bean工厂,用于生成代理对象解决循环依赖。
16.Spring 框架中有哪些注解?
用于声明 Bean 的注解:
@Component:定义通用Bean的注解,可标注任意类为 Bean。如果一个 Bean 不知道属于哪
个层,可以使用@Component 注解标注。
@Repository:定义数据访问层Bean的注解。
@service:定义业务层Bean的注解。
@Controller:定义控制器Bean的注解。
用于注入的注解:
@Autowired:按类型自动注入
@Qualifier:按名称自动注入
声明配置、扫描、启用特性的注解:
@Configuration:声明配置类
@ComponentScan:组件扫描
@EnableScheduling:启用任务调度
@EnableAspectJAutoProxy:启用自动代理工厂
17.Spring框架中用到的设计模式
工厂模式:Spring 使用工厂模式,通过BeanFactory 或 ApplicationContext 来创建对象;
单例模式:Bean 默认作用域为单例,按照单例设计模式进行设计实现;
策略模式:Resource的实现类,针对不同的资源文件,实现了不同方式的资源获取策略;
代理模式:Spring的AOP的实现依靠动态代理(JDK的反射和CGLIB);
模板方法:Spring 提供了JdbcTemplate,RedisTemplate 等模板对象,将相同的操作步骤进行
了封装;
适配器模式:Spring AOP 的增强或通知(Advice)使用到了适配器模式,Spring MVC 中也用
到了适配器模式适配 Controller;
18.Spring 框架中AOP的基本理解
AOP(Aspect-Oriented Programming:面向切面编程):将那些与业务无关,却为业务模块所共
同调用的逻辑(例如事务处理、日志管理、权限控制等)封装抽取成一个可重用的模块,这个模块被
命名为“切面”(Aspect),便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可
拓展性和可维护性;
19.AOP的实现原理
Spring AOP 基于动态代理实现:
如果被代理的对象,已经实现某个接口,则Spring AOP 会使用 JDK Proxy(反射),基于
接口的方式,创建代理对象(JDK 动态代理的核心是InvocationHandler 接口和 Prox
y类);
如果被代理的对象,没有实现某个接口,就无法使用JDK Proxy 去进行代理了,这时候Spri
ng AOP 会使用Cglib,基于继承的方式,生成一个被代理对象的子类来作为代理(Cgli
b 动态代理的核心是MethodInterceptor 接口和Enhancer 类);
20.Spring AOP有哪些通知类型?
前置通知:实现 MethodBeforeAdvice 接口,在目标方法调用前,执行通知;
环绕通知:实现MethodInterceptor 接口,是一个包围目标方法的通知。环绕通知可以在方法调
用前后完成自定义的行为
后置通知:实现AfterReturningAdvice 接口,在在目标方法调用后,执行通知(如果方法抛出异
常,则不执行通知);
异常通知:实现 ThrowsAdvice 接口,在方法抛出异常时,执行通知;猿究
21.Spring 管理事务的方式有几种?
编程式事务:在代码中硬编码(不推荐使用):通过 TransactionTemplate 或者 TransactionM
anager 手动管理事务,实际应用中很少使用,用于理解 Spring 事务管理。
声明式事务:在XML 配置文件或者基于注解@Transactional(推荐使用),通过 AOP实
现。
22.Spring 事务中有哪几种事务传播行为?
1. TransactionDefinition.PROPAGATION_REQUIRED
如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。@Transactiona
注解默认使用的事务传播行为。
2. TransactionDefinition.PROPAGATION_REQUIRES_NEW
创建一个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事
务,Propagation.REQUIRES_NEW 修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。
3. TransactionDefinition.PROPAGATION_NESTED
如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值
等价于 TransactionDefinition.PROPAGATION_REQUIRED。
4. TransactionDefinition.PROPAGATION_MANDATORY
如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:代表强制性)
5. TransactionDefinition.PROPAGATION_SUPPORTS
如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
6. TransactionDefinition.PROPAGATION_NOT_SUPPORTED
以非事务方式运行,如果当前存在事务,则把当前事务挂起。
7. TransactionDefinition.PROPAGATION_NEVER
以非事务方式运行,如果当前存在事务,则抛出异常。
23.Spring 事务中有哪几种事务隔离级别?
1. TransactionDefinition.ISOLATION_DEFAULT 默认隔离级别
使用当前数据库的默认隔离级别,MySQL 默认采用的是可重复读 REPEATABLE_READ 隔离级别。Oracle 默认采用的是读已提交 READ_COMMITTED 隔离级别.
2. TransactionDefinition.ISOLATION_READ_UNCOMMITTED 读未提交
最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
3. TransactionDefinition.ISOLATION_READ_COMMITTED 读已提交
,可以阻止脏读,但是幻读或不可重复读仍有可能发生
允许读取并发事务已经提交的数据,可以阴止脏这
4. TransactionDefinition.ISOLATION REPEATABLE READ
对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重
复读,但幻读仍有可能发生。
那父土。
5. TransactionDefinition.ISOLATION_SERIALIZABLE 串行化
最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不
可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
24.Spring事务在什么情况下会失效?
1.数据库不支持事务
Spring 事务生效的前提是所连接的数据库要支持事务,如果底层的数据库都不支持事务,则Spring的事务肯定会失效。例如:如果使用的数据库为MySQL,并且选用了MyISAM 存储引擎,则Spring的事务就会失效。
2.事务方法未被Spring管理
如果事务方法所在的类没有加载到Spring IOC 容器中,也就是说,事务方法所在的类没有被 Spri
ng 管理,则Spring 事务会失效。例如:ProductService 类上没有标注@Service 注解,Produc
t 的实例没有加载到Spring IOC 容器中,就会造成 updateProductStockCountById()方法的事务
在Spring中失效。
3.方法没有被public修饰
如果事务所在的方法没有被 public 修饰,此时Spring的事务会失效,例如:虽然ProductServ
ice 上标注了@Service 注解,同时updateProductStockCountById()方法上标注了@Transactio
nal(propagation = Propagation.REQUIRES_NEW)注解。
但是,由于updateProductStockCountById()方法为内部的私有方法(使用private修饰),
那么此时updateProductStockCountById()方法的事务在Spring 中会失效。
4. 同一类中方法调用
如果同一个类中的两个方法分别为A和B,方法A上没有添加事务注解,方法B上添加了@Transactional 事务注解,方法A调用方法B,则方法B的事务会失效。例如:submitOrder()方法和updateProductStockCountById()方法都在OrderService 类中,submitOrder()方法上没有标注事务注
解,updateProductStockCountById()方法上标注了事务注解,submitOrder()方法调用了updat
eProductStockCountById()方法,此时,updateProductStockCountById()方法的事务在Sprin
g 中令失效
5.未配置事务管理器