Spring常见面试题

1. 什么是Spring?谈谈你对IOC和AOP的理解?

Spring是企业级的Java应用框架,它的作用是简化软件的开发以及配置过程,简化项目部署环境。
spring-core包实现了ioc容器,spring-aop下实现了aop,spring-web包下对于servlet的一些封装等(讲解下Spring一些常见的jar包)

Spring的优点

  1. Spring是属于低侵入设计,对于业务代码的污染度非常低
  2. Spring的DI机制将对象之间的关系交给框架来吃力,减少了组件的耦合性
  3. Spring提供了AOP技术,支持一些通用的功能进行集中式的管理,从而提供更好的复用,比如我们可以将权限用aop来作,代码的执行时间等,这样就可以形成非常好的代码复用
  4. Spring对于主流框架提供了非常好的支持

IOC就是控制翻转,是指创建对象的控制权转移给Spring来进行管理,简单来说,就是应用不用去new对象了,全部交由Spring自动生产.
IOC有三种注入方式:

  1. 构造注入
  2. set方法注入
  3. 根据注解注入

AOP是面向切面.用于将那些与业务无关,但却对多个对象产生影响的公共行为,抽取并封装成一个可重用的模块.
AOP的核心就是动态代理.
而动态代理分为 JDK的动态代理 和 CGLIB动态代理

2.Spring容器的启动流程是怎么样的?

使用AnnotationConfigApplicationContext来跟踪一下启动流程

        this(); 
        初始化了reader和scanner
	scan(basePackages);使用scanner组件去扫描basePackage下的所有对象,将配置类的BeanDefinition注册到容器中

	refresh(); 刷新容器
		prepareRefresh() 刷新前的预处理
		obtainFreshBeanFactory  获取在容器初始化时创建的BeanFactory
		prepareBeanFactory BeanFactory的预处理工作,向容器中添加一些组件
		postProcessBeanFactory 子类重写该方法,可以实现在BeanFactory创建并预处理完成后做进一步的设置
		invokeBeanFactoryPostProcessors 在BeanFactory初始化之后执行BeanFactory的后置处理器
		registerBeanPostProcessors 向容器中注册Bean的后置处理器,它的主要作用就是干预Spring初始化Bean的流程,完成代理,自动注入,循环依赖等这些功能
		initMessageSource 初始化messagesource组件,主要用于国际化
		initApplicationEventMulticaste 初始化事件分发器
		onRefresh 留给子容器,子类重写的方法,在容器刷新的时候可以自定义一些逻辑
		registerListeners 注册监听器
		finishBeanFactoryInitialization 完成BeanFactory的初始化,主要作用是初始化所有剩下的单例Bean
		finishRefresh 完成整个容器的初始化,发布BeanFactory容器刷新完成的事件

3.Spring框架中Bean的创建过程是怎样的?

首先简单来说,Spring框架的Bean经过四个阶段:

实例化->属性赋值->初始化->销毁
Spring中Bean经过了具体步骤

  1. 实例化: new对象有两个时机
    1) 当客户端申请一个Bean时
    2) 当容器在初始化一个Bean时发现还需要依赖另外一个Bean,BeanDefinition对象保存
    在这里是new一个对象还是创建一个动态代理对象看有没有配置aop

  2. 设置对象属性(依赖注入): Spring通过BeanDefinition找到对象依赖的其他对象,并将这些对象赋予当前对象

  3. 处理aware接口: Spring会检测对象是否实现了xxxAware接口,如果实现了就会调用对应的方法
    比如 BeanNameAware,BeanClassLoaderAware,BeanFactoryAware,ApplicationContextAware

  4. BeanPostProcessor前置处理: 调用BeanPostProcessor的postProcessBeforeInitialization方法

  5. InitializingBean: Spring检查对象如果实现了这个接口,就会执行它的afterPropertiesSet方法,定制初始化逻辑

  6. init-method: 如果Spring发现Bean配置了这个属性,就会调用他的配置方法,执行初始化逻辑.@PostConstruct

  7. BeanPostProcessor后置处理: 调用BeanPostProcessor的postProcessorAfterInitialization方法
    到这里,这个Bean的创建过程就完成了,Bean就可以正常使用了.

  8. DisposableBean: 当Bean实现了这个接口,在对象销毁前就会调用destory方法

  9. destory-method: @PreDestory

4.Spring框架中的Bean是线程安全的吗?如果线程不安全,要如何处理?

Spring容器本身没有提供Bean的线程安全策略,因此,也可以说Spring容器中的Bean不是线程安全的.
要如何处理线程安全问题,就要分情况来看:

Spring作用域:

  1. 默认是sigleton
  2. prototype 为每个Bean请求创建个实例
  3. request 为每个request请求创建一个实例,请求完成后失效
  4. session 与request类似
  5. global-session 全局作用域
    对于线程安全问题
  6. 对于prototype作用域,每次都是生成一个新的对象,所以不存在线程安全的问题
  7. 对于singleton作用域,默认就是线程不安全的.但是对于开发中大部分的Bean,其实是无状态的,不需要保证线程安全,所以在平常的MVC开发中,是不会有线程安全问题的.

无状态表示这个实例没有属性对象,不能保存数据,是不变的类,比如controller,service,dao
有状态表示实例是有属性对象,可以保存数据,是线程不安全的,比如pojo
但是如果要保证线程安全,可以将Bean的作用域改为prototype,比如像Model View
另外还可以采用ThreadLocal来解决线程安全问题。ThreadLocal为每个线程保存一个副本变量,每个线程只操作自己的副本变量

5.Spring如何处理循环依赖问题?

循环依赖: 多个对象之间存在循环的引用关系,在初始化过程当中,就会出现"先有蛋还是先有鸡"的问题。
解决循环依赖有两种方式:

  1. 使用@Lazy,解决构造方法造成的循环依赖问题
  2. 使用三级缓存:
    • 一级缓存sigletonObjects: 缓存最终的单例池对象
    • 二级缓存earlySingletonObjects: 缓存初始化的对象
    • 三级缓存sigletonFactories: 缓存对象的ObjectFactory
      对于对象之间的普通引用,二级缓存就会保存new出来的不完整对象,这样当单例池中找不到依赖的属性时,就可以先从二级缓存中获取到不完整的对象,完成对象创建,在后续的依赖注入过程中,将单例池中对象的引用关系调整成功.
      三级缓存: 如果引用的对象配置了AOP,拿在单例池中最终就会需要注入动态代理对象,而不是原始对象.而生成动态代理是要在对象初始化完成之后,才开始的.于是Spring增加了三级缓存,保存所有对象的动态代理配置信息.在发现有循环依赖时,将这个对象的动态代理信息获取出来,提前进行AOP,生成动态代理.
      核心代码就在DefaultSingletonBeanRegistry的getSingleton方法当中.

6.Spring如何处理事务?

Spring当中支持编程式事务管理和声明式事务管理两种方式
1.编程式事务可以使用TransactionTemplate.
2.声明式事务: 是Spring在Aop基础上提供的事务实现机制.它最大的有点就是不需要在业务代码中添加事务管理的代码,只需要在配置文件中做相关的事务规则的生命就可以了.但是声明式事务只能针对方法级别,无法控制代码级别的事务管理.

Spring中对事务定义了不同的传播级别: Propagation

  1. PROPAGATION_REQUIRED: 默认传播行为.如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入到事务中
  2. PROPAGATION_SUPPORTS: 如果当前存在事务,就加入该事务,如果当前不存在事务就以非事务方式运行
  3. PROPAGATION_MANDATORY: 如果当前存在事务,就加入该事务,如果当前不存在事务就抛出异常
  4. PROPAGATION_REQUIRES_NEW: 无论当前存不存在事务,都会创建新事务进行执行
  5. PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,就将当前事务挂起
  6. PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,就抛出异常
  7. PROPAGATION_NESTED: 如果当前存在事务,则在嵌套事务内执行.如果当前没有事务,就按REQUIRED属性执行

Spring中事务的隔离级别:

  1. ISOLATION_DEFAULT: 使用数据库默认的事务隔离级别
  2. ISOLATION_READ_UNCOMMITTED: 读未提交.允许事务在执行过程中读取其他事务未提交的数据
  3. ISOLATION_READ_COMMITTED: 读已提交.允许事务在执行过程中,读取其他事务已经提交的数据
  4. ISOLATION_REPEATABLE_READ: 可重复读.在同一个事务内,任意时刻的查询结果是一致的
  5. ISOLATION_SERIALIZABLE: 所有事务依次执行

7.SpringMVC中的控制器是不是单例模式?如果是,如何保证线程安全?

控制器是单例模式.

单例模式下就会有线程安全问题.
Spring中保证线程安全的方法

  1. 将scope设置成非sigleton,prototype,request.
  2. 最好的方式是将控制器设置成无状态模式.在控制器中,不要携带数据.但是可以引用无状态的service和dao
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

枫吹过的柚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值