失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > spring 源码深度解析_spring源码解析之SpringIOC源码解析(下)

spring 源码深度解析_spring源码解析之SpringIOC源码解析(下)

时间:2019-08-06 07:21:44

相关推荐

spring 源码深度解析_spring源码解析之SpringIOC源码解析(下)

前言:本篇文章接SpringIOC源码解析(上),上一篇文章介绍了使用XML的方式启动Spring,介绍了refresh方法中的一些方法基本作用,但是并没有展开具体分析。今天就和大家一起撸一下refresh 里边方法内容,做深入解析。

头条上篇文章发代码块发现乱码,今天咱们就以贴图为主来做分析。首先回顾一下refresh方体内容

prepareRefresh()

这里方法中 initPropertySources() 主要是 初始化加载配置文件方法,并没有具体实现,使用户的扩展点,还有一个方法validateRequiredProperties() 这个方法主要是校验环境变量值为空的时候抛出异常,然后阻止spring启动。基于这个特性我们可以把一些必须的变量 提前放在集合requiredProperties中,比如生产环境数据库呀等等。

obtainFreshBeanFactory()

这个方法中主要核心是 refreshBeanFactory() 方法所以这里只看这个方法,下图是我这边源码编译后加了一些注解(自己理解),大家也可以参照 之前文章 idea编译spring源码总结 去编译自己源码

可以看到在最开始的时候这块就实例化了一个DefaultListableBeanFactory 大家可以自行看一下这个类类图。

可以看到它继承了很多类,也实现了很多类。这里边我就挑其中的几个说一下其中的作用

BeanFactory接口:它是所有工厂类的超类,主要定义了对bean的获取、判断bean是否存在、是否为单例等功能;

AutowireCapableBeanFactory接口:这是一个自动注入的ioc bean工厂接口,它继承了BeanFactory接口;实现AutowireCapableBeanFactory接口的工厂需要完成自动注入;

SingletonBeanRegistry接口:这是一个单例的bean工厂。为共享bean实例定义注册表的接口。 可以通过{@link org.springframework.beans.factory.BeanFactory}实现来实现,以便以统一的方式公开它们的单例管理工具

ConfigurableListableBeanFactory:配置接口由大多数可列出的bean工厂实现。 除了{@link ConfigurableBeanFactory}之外,它还提供了分析和修改bean定义以及预先实例化单例的工具

BeanDefinitionRegistry:包含bean定义的注册表的接口,例如RootBeanDefinition和ChildBeanDefinition实例。 通常由BeanFactories实现,BeanFactories内部使用AbstractBeanDefinition层次结构。

说完DefaultListableBeanFactory 我们再说一下loadBeanDefinitions() 方法。在说loadBeanDefinitions()之前首先必须了解 BeanDefinition。我们知道BeanFactory是一个Bean容器,而BeanDefinition就是Bean的一种形式(它里面包含了Bean指向的类、是否单例、是否懒加载、Bean的依赖关系等相关的属性)。BeanFactory中就是保存的BeanDefinition。

再看loadBeanDefinitions()

调用的loadBeanDefinitions()

第一个if是看有没有系统指定的配置文件,如果没有的话就走第二个if加载我们最开始传入的`classpath:application-ioc.xml`、我们跟着`loadBeanDefinitions()`方法往下走,最终会进入类XmlBeanDefinitionReader,这是因为我们这里要解析的配置文件是XML。,如果我们使用Java类配置或者是Groovy的话就是另外的类了。这里我就不具体展开,继续往下走基于咱们这个xml 就是获取到xml配置文件 ,解析bean标签

解析完bean 然后创建BeanDefinition。然后继续看红圈里边的图就是注册bean.

到这里已经初始化了 Bean 容器,的配置也相应的转换为了一个个BeanDefinition,然后注册了所有的BeanDefinition到beanDefinitionMap.

因为篇幅原因这块咱们直接跳到最后来看一个核心、重点

finishBeanFactoryInitialization

刚才我们提到了bean还没有初始化。这个方法就是负责初始化所有的没有设置懒加载的singleton bean 这里我直接跳到主要方法里边

@Overridepublic void preInstantiateSingletons() throws BeansException {if (this.logger.isDebugEnabled()) {this.logger.debug("Pre-instantiating singletons in " + this);}// Iterate over a copy to allow for init methods which in turn register new bean definitions.// While this may not be part of the regular factory bootstrap, it does otherwise work fine.List beanNames = new ArrayList<>(this.beanDefinitionNames);// Trigger initialization of all non-lazy singleton beans...// 触发所有非懒加载方式的单例bean的创建for (String beanName : beanNames) {RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);// 如果bean不是抽象的,而且是单例的,同时还不是懒加载的,则进行下面的操作if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {// 如果bean是一个工厂bean,则走下面的方法if (isFactoryBean(beanName)) {Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);if (bean instanceof FactoryBean) {final FactoryBean> factory = (FactoryBean>) bean;boolean isEagerInit;if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {isEagerInit = AccessController.doPrivileged((PrivilegedAction)((SmartFactoryBean>) factory)::isEagerInit,getAccessControlContext());}else {isEagerInit = (factory instanceof SmartFactoryBean &&((SmartFactoryBean>) factory).isEagerInit());}if (isEagerInit) {getBean(beanName);}}}else { // 普通bean走下面的方法getBean(beanName);}}}// Trigger post-initialization callback for all applicable beans...for (String beanName : beanNames) {Object singletonInstance = getSingleton(beanName);if (singletonInstance instanceof SmartInitializingSingleton) {final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction) () -> {smartSingleton.afterSingletonsInstantiated();return null;}, getAccessControlContext());}else {smartSingleton.afterSingletonsInstantiated();}}}}

可以看到,不管是不是FactoryBean,最后都调用了`getBean(beanName)`,继续看这个方法吧

最后调用的是AbstractBeanFactory 类中doGetBean 的方法。基本流程一开始会先判断bean存不存在,如果存在就直接返回了。如果不存在那就要接着往下看createBean()方法。然后会调用创建bean实例createBeanInstance (),继续就是bean的属性注入populateBean ()基本getBean 就算完事了。

OK,在这里源码部分就到这里了。在下边整理了一些问题

spring应用的入口在哪?

Spring基础就是一个IoC容器(BeanFactory),目前我们使用的是ApplicationContext对象去创建IoC容器(高级IoC容器)

BeanFactory和FactoryBean的区别

BeanFactory:它是存放Bean的工厂

FactoryBean:它是一个需要被存放在BeanFactory中的一个JavaBean,只是这个JavaBean的作用是为了产生另一些JavaBean。

BeanFactoryPostProcessor 和 BeanFactoryPostProcessor

BeanFactoryPostProcessor:BeanFactory后置处理,器作用是为了对BeanDefinition对象进行修改

BeanPostProcessor:Bean后置处理器,作用是为了对生成的Bean对象进行修改

Spring如何解决循环依赖问题

所谓的循环依赖是指:A 依赖 B,B 又依赖 A,它们之间形成了循环依赖。或者是 A 依赖 B,B 依赖 C,C 又依赖 A。

IOC 容器在读到上面的配置时,会按照顺序,先去实例化 beanA。然后发现 beanA 依赖于 beanB,接在又去实例化 beanB。实例化 beanB 时,发现 beanB 又依赖于 beanA。如果容器不处理循环依赖的话,容器会无限执行上面的流程,直到内存溢出,程序崩溃。当然,Spring 是不会让这种情况发生的。在容器再次发现 beanB 依赖于 beanA 时,容器会获取 beanA 对象的一个早期的引用(early reference),并把这个早期引用注入到 beanB 中,让 beanB 先完成实例化。beanB 完成实例化,beanA 就可以获取到 beanB 的引用,beanA 随之完成实例化。这里大家可能不知道“早期引用”是什么意思,所谓的”早期引用“是指向原始对象的引用。所谓的原始对象是指刚创建好的对象,但还未填充属性。可能在这里不太好理解大家可以结合源码分析,下边简单说明一下

1.创建原始 bean 对象

instanceWrapper = createBeanInstance(beanName, mbd, args);

final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);

假设 beanA 先被创建,创建后的原始对象为 BeanA@12,上面代码中的 bean 变量指向就是这个对象。

2. 暴露早期引用

addSingletonFactory(beanName, new ObjectFactory() { @Override public Object getObject() throws BeansException { return getEarlyBeanReference(beanName, mbd, bean); }});

beanA 指向的原始对象创建好后,就开始把指向原始对象的引用通过 ObjectFactory 暴露出去。getEarlyBeanReference 方法的第三个参数 bean 指向的正是 createBeanInstance 方法创建出原始 bean 对象 BeanA@12。

3. 解析依赖

populateBean(beanName, mbd, instanceWrapper);

populateBean 用于向 beanA 这个原始对象中填充属性,当它检测到 beanA 依赖于 beanB 时,会首先去实例化 beanB。beanB 在此方法处也会解析自己的依赖,当它检测到 beanA 这个依赖,于是调用 BeanFactry.getBean("beanA") 这个方法,从容器中获取 beanA。

4. 获取早期引用

protected Object getSingleton(String beanName, boolean allowEarlyReference) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { // 从缓存中获取早期引用 singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) {ObjectFactory> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {// 从 SingletonFactory 中获取早期引用singletonObject = singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);} } } } return (singletonObject != NULL_OBJECT ? singletonObject : null);}

接着上面的步骤讲,populateBean 调用 BeanFactry.getBean("beanA") 以获取 beanB 的依赖。getBean("beanA") 会先调用 getSingleton("beanA"),尝试从缓存中获取 beanA。此时由于 beanA 还没完全实例化好,于是 this.singletonObjects.get("beanA") 返回 null。接着 this.earlySingletonObjects.get("beanA") 也返回空,因为 beanA 早期引用还没放入到这个缓存中。最后调用 singletonFactory.getObject() 返回 singletonObject,此时 singletonObject != null。singletonObject 指向 BeanA@12,也就是 createBeanInstance 创建的原始对象。此时 beanB 获取到了这个原始对象的引用,beanB 就能顺利完成实例化。beanB 完成实例化后,beanA 就能获取到 beanB 所指向的实例,beanA 随之也完成了实例化工作。由于 beanB.beanA 和 beanA 指向的是同一个对象 BeanA@12,所以 beanB 中的 beanA 此时也处于可用状态了。

如果觉得《spring 源码深度解析_spring源码解析之SpringIOC源码解析(下)》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。