Spring常见面试题之我见

83 阅读6分钟

我正在参加「掘金·启航计划」

1.谈谈你对IOC的理解,原理与实现

控制反转:原本对象的创建是由使用者去创建,现在将对象的创建交个spring容器去管理。
其实现方式就是通过DI完成的,使用到的场景就是@AutoWired、pupluteBean等
容器:存储对象,使用map结构来存储,整个bean的生命周期,从创建到使用到销毁的过程
都是由容器来管理整体实现可以划分为以下步骤来说明:
   1. 创建容器(beanFactory、DefaultLisableBeanFactory),向bean工程设置参数
   2. 加载并解析bean对象,准备要创建的bean对象的定义对象beanDefinition(配置文件
   或者注解修饰的类)
   3. beanFactoryPostProcessor的处理, 执行invokeBeanFactoryPostProcessor方法,
   此处是springBoot自动装配代码的实现处,重要的类是ConfigurationClassBeanPostProcess
   4. 注册BeanPostProcessor接口的实现,方便后续对bean对象完成具体的扩展功能
   5. 注册到容器中对象的实例化
   6. bean对象的初始化过程(实例化=》初始化=》填充属性=》=》执行aware接口=》
   beanPostProcessor的前置方法=》执行init-method方法=》执行beanPostProcessor
   的后置方法=》销毁)
   7. 生成完整的bean对象,
   8. 销毁

2.谈一下IOC的底层实现

1. 通过createBeanFactory创建出一个bean工厂
2. 开始循环创建对象
3. 通过createBean、doCreateBean方法,以反射的方式创建对象。
4. 进行属性的填充
5. 进行其他的初始化操作

3.描述一下bean的生命周期

实例化=》初始化=》填充属性=》=》执行aware接口=》beanPostProcessor的前置方法=》执行init-method方法=》执行beanPostProcessor的后置方法=》销毁

image.png

4.Spring是如何解决循环依赖的问题

产生原因

循环依赖的原因:A依赖B、B依赖A。具体的产生原因是:
1、创建A对象,实例化A对象,此时A对象中的b属性为空,填充b属性
2、从容器中查找b对象,没有找到,则创建b对象
3、创建B对象,实例化B对象,此时B对象中a属性为空,填充a属性
4、从容器中查找a对象,找不到,则创建a对象,由此形成闭环

解决思路

      此时,如果仔细琢磨的话,会发现A对象是存在的,只不过此时的A对象不是一个完整的状态
  ,只完成了实例化但是没有完成初始化的状态,如果在程序调用过程中,拥有了某个对象的引用
  ,能否在后期给他完成赋值操作。可以优先把非完整状态的对象优先赋值,等待后续操作来完成
  赋值,相当于提前暴露了某个不完整对象的引用,所以解决问题的核心在于实例化和初始化分开
  操作。
      当所有的对象都完成实例化和初始化操作之后,还要把完整对象放到容器中,此时在容器中
  存在对象的几个状态,完成实例化但未完成初始化,完整状态,因为都在容器中,所以要使用不
  同的map结构来进行存储,此时就有了一级缓存和二级缓存,如果一级缓存中有了,那么二级缓
  存中就不会存在同名的对象,因为他们的查找顺序是1,2,3这样的方式来查找。一级缓存中放
  的是完整对象,二级缓存中存的是非完整对象
      为什么要用三级缓存?三级缓存的value类型是ObjectFactory,是一个函数式接口,存在
  的意义是保证在整个容器的运行过程中那个同名的bean对象只能有一个.如果一个对象需要被代理
  ,或者说需要生成代理对象,得先生成一个普通对象
      普通对象和代理对象是不能同时出现在容器中的,因此当一个对象需要被dialing的时候,
  就要使用代理对象覆盖掉之前的普通对象,在实际的调用过程中,是没有办法确定什么时候对象
  被使用,所以就要求当某个对象被调用的时候,优先判断此对象是否需要被代理,类似于一个回
  调机制的实现,因此传入lambda表达式。可以通过执行对象的覆盖过程getEarlyBeanReference
  因此,所有的bean对象在创建的时候都要优先放入到三级缓存中,在后续的使用过程中,如果需要
  被代理则返回代理对象,否则直接返回普通对象

5.BeanFactory与FactoryBean有什么区别

相同点:创建bean对象
不同点:使用beanFactory创建对象的时候,必须遵循严格的生命周期,使用FactoryBean接口创建
的对象,
只需要实现FactoryBean接口的三个方法(isSingleton、getObjectType、getObject)即可

6.Spring中用到的设计模式

  • 单例模式:bean都是单例的
  • 工厂模式:BeanFactory
  • 模板方法:onRefresh、postProcessBeanFactory
  • 观察者模式:listener、event、multicast
  • 适配器模式:Adapter
  • 装饰者模式:BeanWrapper

7.SpringAOP的底层实现原理

  aop是动态代理,bean的创建过程中有一个步骤可以对bean进行扩展实现,aop本身就是一个
扩展功能,所以在BeanPostProcessor的后置处理方法中进行实现
  通过jdk或者cglib的方式来生成代理对象,在执行方法调用的时候,会调用到生成的字节码文件中,
直接回找到DynamicAdvisoredInterceptor类中的intercept方法,从此方法开始执行
  根据之前定义好的通知来生成拦截器链

8.Spring事务时如何回滚

  spring的事务是由aop来实现的,首先要生成具体的代理对象,然后按照aop的整套流程来执行
具体的操作逻辑,正常情况下要通过通知来完成核心功能,但是事务不是通过通知来实现的,而是
通过一共TransacationInterceptor来实现的,然后调用invoke来实现具体的逻辑
  1、 解析各个方法上事务相关的属性,根据具体的属性来判断是否开始新事务
  2、 当需要开启的时候,获取数据库连接,关闭自动提交功能,开启事务
  3、 执行具体的sql逻辑操作
  4、 在操作过程中,如果执行失败,通过completeTransactionAfterThrowing完成事务的
回滚操作,回滚的具体逻辑是通过doRollBack方法来实现的,实现的时候要先获取数据库连接
对象,通过连接对象进行回滚操作
  5、 如果执行过程中,没有任何意外情况的发生,通过commitTransactionAfterReturning
来完成事务的提交操作,提交的具体逻辑是通过doCommit方法来实现的,实现的时候也是先获取
数据库连接,通过连接对象进行提交操作
  6、 当事务执行完毕之后需要清楚相关的事务信息,cleanUpTransactionInfo  

9.谈一下spring事务传播?

  传播特性一共有7种,
Required,Required_new,nested,Support,Not_support,Never,Mandatory
  事务的传播特性指的是不同放啊的嵌套调用过程中,事务应该如何进行处理,是用同一个事务,
还是不同的事务,当出现异常的时候会回滚还是提交,两个方法之间的相关影响。
  在日常使用比较多的是required,requires_new,nested