SpringIOC源码解析过程,及解决循环依赖详解

xml解析:

  • XmlBeanFactory继承自DefaultListableBeanFactory,XmlBeanFactory使用XmlBeanDefinitionReader的loadBeanDefinitions方法将xml的Resource资源进行解析和读取。
  • XmlBeanDefinitionReader将xml资源委托给DefaultDocumentLoader类的loadDocument方法将xml的Resource转换为Document资源返回给XmlBeanDefinitionReader,XmlBeanDefinitionReader调用registerBeanDefinitions方法将Document资源委托给DefaultBeanDefinitionDocumentReader,DefaultBeanDefinitionDocumentReader调用parseBeanDefinitions方法对Document资源的各个节点 进行解析并注册。
  • 注册主要是DefaultBeanDefinitionDocumentReader的parseBeanDefinitions方法中调用了BeanDefinitionParserDelegate类的parseBeanDefinitionElement方法对Document的节点解析成BeanDefinitionHolder,BeanDefinitionHolder中封装了beanName、BeanDefinition、Aliases等属性。
  • 然后调用DefaultListableBeanFactory核心类的registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())方法完成BeanDefinition的向ioc容器注册,ioc容器就是以DefaultListableBeanFactory内部的一个ConcurrentHashMap作为存储存储媒介

单例bean的加载创建:

AbstractBeanFactory类getBean方法中的doGetBean这个方法蕴含了整个bean的依赖注入、bean的创建、属性赋值、初始化、后置处理器的前后置方法的调用、循环依赖解决等。
doGetBean方法主要有两个分支,分支一:从缓存取bean,分支二:缓存中不存在bean,从头开始创建bean

从缓存取bean
  • doGetBean中先通过getSingleton(beanName)获取缓存中的对应beanName的原始对象,然后调用getObjectForBeanInstance方法对应原始对象进行还原,创建出来的bean都要经过getObjectForBeanInstance方法才能完成创建,原因是创建出来的bean可能是一个factorybean工厂对象,所以需要调用此方法,内部会判断如果是一个factorybean,就会调用其getObject方法还原bean,还原后直接返回
  • 为解决单例模式的循环依赖,在spring创建bean的时候是不等bean创建完成就将创建的objectFactory提前曝光加入缓存中,一旦下一个bean创建需要依赖上一个bean的时候则直接使用objectFactory
    getSingleton 方法涉及了spring的三级缓存:
    singletonObjects:第一级缓存,存放可用的完全初始化,成品的Bean。存放的是beanName与bean实例
    earlySingletonObjects:第二级缓存,存放半成品的Bean,半成品的Bean是已实例化好的对象,但是未注入属性和初始化,这个bean对象有可能是个AOP代理的bean。用来处理被AOP代理后的bean的循环依赖问题,这里主要是存放的是beanName与正在创建的bean实例,这个bean有可能是已经创建好的代理的bean。如下面的代码,从三级缓存singletonFactories取出的singletonFactory.getObject()方法其实就是调用匿名函数的getEarlyBeanReference方法,这个方法内部会调用SmartInstantiationAwareBeanPostProcessor后置处理器的getEarlyBeanReference方法里的wrapIfNecessary方法生成代理。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        // Quick check for existing instance without full singleton lock
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                synchronized (this.singletonObjects) {
                    // Consistent creation of early reference within full singleton lock
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
                        singletonObject = this.earlySingletonObjects.get(beanName);
                        if (singletonObject == null) {
                            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                            if (singletonFactory != null) {
                                singletonObject = singletonFactory.getObject();
1、----------------------------------------------------缓存到二级缓存中-----------------------------------------------
                                this.earlySingletonObjects.put(beanName, singletonObject);
                                this.singletonFactories.remove(beanName);
                            }
                        }
                    }
                }
            }
        }
        return singletonObject;
    }
2、--------------------------------------------------在调用createBeanInstance实例化bean后会保存bean到三级缓存中------------------------------------------------
addSingletonFactory(beanName, new ObjectFactory() {
                public Object getObject() throws BeansException {
                    return getEarlyBeanReference(beanName, mbd, bean);
                }
            });
3、------------------------SmartInstantiationAwareBeanPostProcessor 后置处理器是AOP会调用AbstractAutoProxyCreator类的getEarlyBeanReference生成AOP的代理----------------------------
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
        Object exposedObject = bean;
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                    SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                    exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                }
            }
        }
        return exposedObject;
    }

可以概括为二级缓存存放的就是那些从三级缓存中取出的objectFactory对象调用getObject()方法返回的对象,这个方法会调用到getEarlyBeanReference方法给那些aop注解对象生成代理,而且这个对象是已经完成实例化但是还未完成属性赋值或者初始化
singletonFactories:第三级缓存,存的是Bean工厂对象。用以解决循环依赖。如果Bean存在AOP的话,返回的是AOP的代理对象,并配合二级缓存解决循环依赖。存放的是beanName与objectFactory,这是解决循环依赖的主要手段。

从头开始创建bean
  • 先判断是否是多例并且存在循环依赖,是则抛出异常,不处理
  • 查找ioc容器中是否包含这个bean,不包含则需要从父类容器中getBean方法创建bean
  • ioc容器中存在此beanName的BeanDefinition,则将此BeanDefinition及其父类的属性合并成RootBeanDefinition
  • 使用RootBeanDefinition.getDependsOn()方法查找这个bean创建需要依赖的对象,先遍历这些属性调用getBean创建这些依赖对象
  • 从RootBeanDefinition判断这个bean是单例还是多例,单例则使用,以下代码创建
//这个getSingleton和上面的getSingleton不一样,是个重载的getSingleton方法 
sharedInstance = getSingleton(beanName, () -> {
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });
                    beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

这里的getSingleton主要是使用匿名函数createBean创建的objectFactory然后调用getObject完成bean的创建初始化,然后将创建好的bean实例singletonObjects一级缓存中, 然后调用getObjectForBeanInstance对原始对象进行还原

  • 这其中createBean是AbstractAutowireCapableBeanFactory的方法,在方法中会调用resolveBeforeInstantiation返回代理做前置处理,如果这个方法返回的bean不为空,则说明bean对象是代理使用前置处理生成的beanbean,不需要容器做后续的创建工作
  • 在createBean方法中如果resolveBeforeInstantiation方法返回的是空对象,那么就需要使用doCreateBean进行创建了,doCreateBean方法是蕴含了bean对象的实例化、属性赋值、实例化的一系列生命周期的方法,其中夹杂了许多前后置的处理调用,这个方法非常关键
单独分析doCreateBean方法

doCreateBean也是AbstractAutowireCapableBeanFactory的方法,是bean进行常规创建的方法。

  • bean的实例化。先使用createBeanInstance方法进行bean的实例化,这是bean生命周期的第一个阶段,里面包含里多种实例化策略,包括了工厂方法、构造函数自动注入、简单初始化等,具体的逻辑是,如果BeanDefinition中包含工厂方法优先使用工厂方法实例化、否则spring会更加参数去锁定使用bean中的哪一个构造方法,如果不是工厂方法也不存在带参数的构造方法,则使用默认是无参构造进行实例化,实例化的bean是以BeanWrapper类型存在,BeanWrapper封装了bean各类消息,通过BeanWrapper.getWrappedInstance返回实例化的bean。
  • 调用完createBeanInstance实例化完bean后,然后spring为了解决循环依赖,会在完成bean创建前调用addSingletonFactory方法,将objectFactory放入三级缓存中,以此解决循环依赖。objectFactory是通过实例化的bean实例去生成的。
  • 这里我们单独说一下spring如何解决循环依赖,spring调用了我们刚刚提到的addSingletonFactory方法,代码如下:
//mbd是RootBeanDefinition,bean是BeanWrapper调用getWrappedInstance()返回的刚刚实例化的bean
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

我们在看看里面的匿名函数:

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
        Object exposedObject = bean;
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
                exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
            }
        }
        return exposedObject;
    }

这里使用了SmartInstantiationAwareBeanPostProcessor的后置处理器的调用,对bean进行处理,aop将advice动态织入也是在这里实现的,也就是基于SmartInstantiationAwareBeanPostProcessor类实现的动态织入,spring如何使用其解决循环依赖依赖的呢?假如此时A创建时需要创建B,B创建时需要A,而此时通过提供objectFactory来填充B的依赖属性A,因为A是正在创建进行中,只进行了实例化,没有进行任何的属性赋值,但是objectFactory就是在此方法中通过刚刚实例化的A的实例bean生成的,所以此objectFactory指向的属性地址是与B中持有的A是一样的,B也只是仅仅需要A类型的属性赋值以便完成创建而已,所以A能填充到B中,这样就解决了循环依赖。这仅仅只是getset方法注入及单例才能解决的循环依赖。如果是构造器注入的话是没有办法解决循环依赖的,原因是A构造器注入时需要一个创建好的B,B构造器注入时需要一个创建好的A,因此A和B没办法实例化,提供一个A或者B属性的对象,这样就没有办法解决循环依赖。但是getset注入就可以使用无参构造一个bean,所以能做到完成属性赋值等一系列操作前暴露一个使用构造好的bean创建的objectFactory去解决循环依赖,并不需要完成创建好。多例模式无法解决循环依赖的是因为bean每次使用时都需要创建一个最新的对象,对象没办法进行复用所以容器不会进行缓存,就无法提前暴露一个bean。
当面试官提问spring如何解决循环依赖时可以这么会答:在单例模式getset注入的情况下,spring的创建bean的过程中,bean进行实例化后会暴露一个objectFactory并存入三级缓存中,在还没有完成bean的创建完成前会使用三级缓存解决循环依赖的问题,如果是AOP代理对象产生的循环依赖会使用二级缓存和三级缓存共同处理,完成bean的创建后就会将对应的二级缓存和三级缓存移除,并存入一级缓存,以便下次使用时可以复用

  • bean的属性赋值,回到doCreateBean方法调用完addSingletonFactory方法之后会使用populateBean方法对bean进行属性赋值,这是bean生命周期的第二个阶段,详细过程是从RootBeanDefinition获取PropertyValues对象,根据条件决定调用autowireByName方法按名称调用还是autowireByType按类型注入,无论是按名称注入还是按类型注入都是根据RootBeanDefinition和BeanWrapper去查找需要注入的依赖bean,然后对这些bean进行循环遍历并调用getBean方法一一创建依赖对象,将依赖对象存储到PropertyValues中,变量后置处理器对PropertyValues中的依赖属性进行后置处理,然后调用applyPropertyValues方法将PropertyValues设置的依赖对象应用到已经实例化好的bean到中,这样就完成了bean的属性赋值
  • bean的初始化,回到doCreateBean方法继续调用initializeBean去完成bean生命周期的第三个阶段:初始化此时bean已经完成了实例化以及属性赋值,这时就会调用用户设定的初始化方法。方法中调用invokeAwareMethods这个方法会调用一系列的xxxxAware类的方法,applyBeanPostProcessorsBeforeInitialization是遍历postPostProcessor的前置方法并调用,applyBeanPostProcessorsAfterInitialization是遍历postPostProcessor的后置方法并调用。
  • 初始化完成后返回实例对象,然后返回到doGetBean方法中,将其传入getObjectForBeanInstance方法将bean进行还原,然后返回

Spring几个重要的拓展点

InstantiationAwareBeanPostProcessor和BeanPostProcessor、BeanDefinitionRegistryPostProcessor
@Component
public class Inintion implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("InstantiationAwareBeanPostProcessor:postProcessBeforeInstantiation");
        System.out.println(beanName+"开始实例化");
        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        System.out.println("InstantiationAwareBeanPostProcessor:postProcessAfterInstantiation");
        System.out.println(beanName+"实例化完成");
        return false;
    }
}

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName+"开始初始化了.......");
        System.out.println("BeanPostProcessor:postProcessBeforeInitialization");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
         System.out.println(beanName+"初始化完成了.......");
        System.out.println("BeanPostProcessor:postProcessAfterInitialization");
        return bean;
    }
}

@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
        rootBeanDefinition.setBeanClass(Hadoop.class);
        registry.registerBeanDefinition("hadoop32", rootBeanDefinition);
        System.out.println("BeanDefinitionRegistryPostProcessor:postProcessBeanDefinitionRegistry===============");
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("BeanDefinitionRegistryPostProcessor:postProcessBeanFactory===============");

    }
}

加载bean观察现象


@Data
@Component
public class Html {
    private Integer id;
    private String name;

    public Html(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Html() {
        System.out.println("html调用了构造方法");
    }

    //@PostConstruct在容器的组件初始化后使用
    @PostConstruct
    public void post() {
        System.out.println("Html调用了@PostConstruct的方法");
    }

    //@PreDestroy在容器的组件被摧毁前被调用
    @PreDestroy
    public void destroy() {
        System.out.println("Html调用了@PreDestroy的方法");
    }
}

结论:

1、InstantiationAwareBeanPostProcessor是在bean实例化前后调用,postProcessBeforeInstantiation是在实例化前执行,postProcessAfterInstantiation是在实例化后执行
2、BeanPostProcessor是在bean初始化前后调用的,postProcessBeforeInitialization是在bean初始化前执行,postProcessAfterInitialization是在bean初始化后执行
3、BeanDefinitionRegistryPostProcessor是在bean的注册前后调用

初始化InitializingBean

spring初始化bean有两种方式:

  • 第一:实现InitializingBean接口,继而实现afterPropertiesSet的方法
@Component
class MyInitializingBean implements InitializingBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean:afterPropertiesSet===============================");
    }
}
  • 第二:反射原理,配置文件使用init-method标签直接注入bean
<bean id="testInitializingBean" class="com.TestInitializingBean" init-method="testInit"></bean>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章