面试真题--------spring源码解析IOC

时间:2021-10-17 01:46:00

spring是我经常使用的框架,可是你真的对spring理解吗? 还是只知道它得使用。如果你想知道它真实的面目请仔细向下看。

1.spring是如何知道哪些Bean需要实例化的?

容器启动过程中,首先调用DispatcherSerlvet的init方法,init方法内部根据web.xml的配置,读取配置的上下文readspring-servlet.xml,然后逐句解析该上下文,当它读取到context:component-scan标签时,就启动对应的解析器,也可以叫做扫描器,对应的Class为:ComponentScanBeanDefinitionParser。这个类ComponentScanBeanDefinitionParser中调用了doScan方法,可以看到传了一个参数:basePackages,就是我们配置的路径。

这样,就读取到了需要被实例化的所有类,之后这些类的信息会被封装成一个一个的BeanDefinition,然后保存到DefaultListableBeanFactory的beanDefinitionMap*后续使用。

    /** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();

2.Spring中Bean是什么时候被实例化的?

所有的这些Bean,在容器启动的时候,已经全部被实例化了。

下面看代码一探究竟,还得看模板方法,AbstractApplicationContext.refresh(),其中有这么一个方法

  // Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

看注释知道:实例化剩下的所有单例。

Spring中的Bean默认都是单例的,除非显示的声明为prototype。

剩下的(remaining)的意思是有一些Spring自身的处理器、解析器等Bean不是在这里实例化的,我们自己编写的常规类Controller、Service等全部都是在此处实例化。

3.实例化的过程

首先循环所有的BeanDefinition列表,然后调用getBean()方法,检查是否被实例化,如果没有被实例化则调用createBean()方法,具体的实例化是利用cglib类库,通过Java反射原理,构造函数实例化方式去实例化。然后组装Bean,把Bean属性设置进去,这里就是依赖注入了,把实例化好的serviceInstance注入到Service中。实例化成功后将实力保存到singletonObjects Map中。

所有的Bean被实例化后,会被存入这个Map*后续使用。

DefaultSingletonBeanRegistry.java

    /** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>();

4.Bean的Scope

  (1)Singleton:一个Spring容器中只有一个Bean的实例,此为Spring的默认配置,全容器共享一个实例。

  (2)Prototype:每次调用新建一个Bean实例。

  (3)Request:Web项目中,给每一个 http request 新建一个Bean实例。

  (4)Session:Web项目中,给每一个 http session 新建一个Bean实例。

  (5)GlobalSession:这个只在portal应用中有用,给每一个 global http session 新建一个Bean实例。

其中request,session和global session只适用于Web应用程序中,通常是与XmlWebApplicationContext一起使用,在实现上,singleton和prototype两种类型的容器的标准类型,而Scope request,session和global session是继承于自定义的Scope接口,如果用户有特殊的需要,可以继承这个接口并注册到容器中,即可使用用户自定义的Scope类型。用户自定义的Scope必须自己维护所管辖对象的初始化及销毁,即容器将这些对象的生存周期委托给Scope管理,而容器只管理Scope对象本身就可以。

5. 注解怎么做到声明接口就可以将实现类注入?

Spring主要利用了Class.isAssignableFrom()方法来实现接口与实现类的匹配。

  Class1.isAssignableFrom(Class2):如果Class1是Class2本身或者是其接口或者父类,则返回true,否则返回false;

以testService的实例化为例,当Spring容器启动的时候,首先会读取配置文件,经过定位、加载、解析、注册,最终把标注了注解的类(例如:标注了@Service的TestServiceImpl)注册到BeanDefination的Map中并且缓存。

然后,在实例化testService的时候,Spring此刻并不知道testService的实现类是哪个,而是循环遍历BeanDefinitionMap中的Bean,逐一与ITestService接口进行类型匹配,一旦匹配上就认定为其实现类,并对其进行实例化。

参考----http://www.cnblogs.com/notDog/p/5420727.html

https://www.cnblogs.com/dyppp/p/7397290.html

https://www.imooc.com/article/19601