Spring面试题总结

目录

1. 聊一下IOC的理解

2. 容器的创建过程

3. bean的生命周期

4. BeanFactory和FactoryBean的区别

5. Spring中用到哪些设计模式

6. BeanFactory和ApplicationContext的区别


1. 聊一下IOC的理解

1.1 什么是IOC,IOC就是控制反转,spring之前开发过程中我们要使用对象都是自己new出来然后进行赋值初始化一系列操作,包括使用完成之后的销毁,都由开发自己控制,spring出现以后,对象的创建、初始化及销毁的过程都交给容器帮我们进行管理,这是IOC的理论思想。

1.2 谈到IOC顺带说一下DI依赖注入,将对应的属性注入到具体的对象中,平时我们在项目中一般是通过@Autowired,@Resource注解来进行注入的。当我们在实际调用的时候,属性的注入还会通过populateBean方法来完成。

1.3 容器:使用map结构来存储对象,在Spring存储对象的时候一般有三级缓存。singletonObjects存放已完成初始化,属性已赋值的完整对象。earlySingletonObjects存放已实例化,属性还未赋值的半成品对象,singletonFactory用来存放创建单例bean的工厂。整个bean的生命周期(从创建到销毁)都是由容器来帮我们控制的。

在IOC体系中还有很多细节的点,我源码是之前看的,而且只看过一遍,记不太清了。Spring中所有的bean都是通过反射的方式创建的,先调用getConstructor()方法获得默认的构造器,再通过调用构造器的newInstance()方法生成bean。在整个流程中还会包含很多扩展点,比如有两个非常重要的接口:BeanFactoryPostProcessor和BeanPostProcessor,用来实现扩展功能,AOP就是通过BeanPostProcessor实现的。


2. 容器的创建过程

容器有refresh()方法进行创建,里面分为12个大的步骤,分别如下:

转载:spring容器创建过程(总结版)_大叶子不小的博客-优快云博客


3. bean的生命周期

  1. 实例化bean对象,通过反射方式来生成,源码中有一个createBeanInstance()方法是专门用来生成对象的。
  2. bean实例化后调用populateBean()方法来填充对象的属性,这里面会利用三级缓存来解决循环依赖问题。
  3. 调用invokeAwareMethod()方法,检查是否实现aware接口
  4. 如果Bean实现了BeanNameAware接口的话,调用setBeanName()方法设置BeanName
  5. 如果Bean实现了BeanFactoryAware接口的话,调用setBeanFactory()方法,设置BeanFactory
  6. 如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。
  7. 如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。使用比较多的有(ApplicationContextPostProcessor,设置Application, Environment, ResourceLoader, EmbedValurResolver等对象)
  8. 调用invokeInitMethods方法来完成初始化方法的调用,如果bean对象实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。
  9. 如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法完成bean对象的后置处理工作,AOP就是在此处实现的,实现的类为AbstractAutoProxyCreator。
  10. 此时,Bean已经准备就绪,通过getBean()方法来获取到具体的对象。
  11. 销毁流程,1、判断是否实现了DisposableBean接口,2、调用destroyMethod方法。

4. BeanFactory和FactoryBean的区别

BeanFactory和FactoryBean都可以用来创建对象,只不过创建的流程和方式不同,当使用      BeanFactory的时候,必须要严格的遵守bean的生命周期,经过一系列繁杂的步骤之后才可以创建出单利对象,是流水线式的创建过程。

        而FactoryBean是用户可以自定义bean对象的创建流程,不需要按照bean的生命周期来创建,在此接口中包含了三个方法:

        1) isSingleton-是否单例。

        2) getObjectType-获取对象的类型。

        3) getObject:在此方法中创建对象,new()、反射、动态代理的方式都可以。

        很多框架集成的时候都会实现FactoryBean接口,比如Feign。


5. Spring中用到哪些设计模式

1)单例模式:spring默认所有的bean都是单例的。

2)原型模式:指定scope="prototype"。

3)工厂模式:BeanFactory。

4)模板方法:postProcessBeanFactory, onRefresh, initPropertyValue

5)观察者模式:listener,event,multicast

6)适配器模式:Adapter

7)装饰者模式:BeanWrapper

8)责任链模式:使用aop的时候会一个调用方法getInterceptorsAndDynamicInterceptionAdvice()

9)代理模式:aop动态代理

10)建造者模式:builder

...


6. BeanFactory和ApplicationContext的区别

BeanFactory是访问spring容器的根接口,里面只是提供了某些基本方法的约束和规范,为了满足更多的要求,ApplicationContext实现了该接口,并在此接口的基础上做了某些扩展功能,提供了更加丰富的api调用。一般我们在使用的时候用ApplicationContext更多。


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

什么是循环依赖?如下图:

解决办法:Spring中bean对象的创建都会经历实例化和初始化(属性填充)两个步骤,通过区分对象的状态,就是半成品状态(未完成属性的填充,但是已有引用)和成品状态(完成了属性的填充)。成品对象存入一级缓存,半成品对象存入二级缓存。三级缓存的value类型为ObjectFactory,这个后面细说。

通过区分不同的状态就能打破前面所描述的循环依赖问题了,当实例化A对象的时候,b属性未完成赋值,此时A对象就是一个半成品对象,这时候将半成品对象A放入二级缓存中,当给B对象中的a属性赋值的时候,优先从一级缓存中找,没找到再去二级缓存中找,这个时候就能找到并成功赋值,这样就打破了循环。

只有一级缓存是不够的,因为这样会把成品状态的bean和半成品状态的bean放在一起,而半成品对象是不能暴露给外部进行使用的。

只有二级缓存也是不够的,因为会涉及到AOP动态代理,代理对象在生成之前一定会先生成一个原始对象,当代理对象生成以后就会同时存在代理对象和原始对象,此时就需要判断我们到底该使用哪一个对象,当需要使用代理对象时,就必须要覆盖掉原始对象,也就是说,整个容器中不会出现两个同名的bean对象。

在实际调用的过程中,是没有办法来确定对象什么时候被使用,因此当某一个对象被调用的时候,优先判断当前对象是否需要被代理,类似回调机制,当获取对象之后根据传入的lambda表达式来确定返回的是原始对象还是代理对象,利用getEarlyBeanReference()方法来处理。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值