Spring IoC源码分析(五)

一、回顾

上回讲到spring在容器启动时需要创建一些单例bean,创建单例bean的过程实际上就是spring创建bean实例的过程,来回顾一下上次的代码,不用全部看完,找到这次需要讲到的createBeanInstance(beanName, mbd, args)方法即可

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
            throws BeanCreationException {

        // BeanWrrapper,Bean包装器,简单理解成对bean赋值的,后面展开
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            //若mbd为单例,需要先判断是否为FactoryBean
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        //如果instanceWrapper为空,则创建一个bean实例
        if (instanceWrapper == null) {
            //createBeanInstance,创建bean实例封装到wrapper中
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        //通过wrapper获取到了bean
        final Object bean = instanceWrapper.getWrappedInstance();
        //处理bean类型
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }
        // 允许post-processors修改mbd
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                 //简单来说就是对mbd做一些加工  
                 applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                    //抛出异常
                    ......
                }
                mbd.postProcessed = true;
            }
        }
        // 解决循环依赖的问题
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            ......
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }
        // bean在实例化后,还需要赋值和初始化(init)
        Object exposedObject = bean;
        try {
            //这一步负责属性装配,关键就在于BeanWrapper
            populateBean(beanName, mbd, instanceWrapper);
            //处理 bean 初始化完成后的各种回调
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {
            //抛出异常
            ......
        }
        //主要用于解决循环引用,这部分先跳过吧
        if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                    for (String dependentBean : dependentBeans) {
                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    if (!actualDependentBeans.isEmpty()) {
                        //抛出异常
                        ......
                    }
                }
            }
        }
        // 注册bean为使用后即销毁
        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            //抛出异常
            ......
        }
        return exposedObject;
}

二、createBeanInstance(beanName, mbd, args)

这个方法一看就很好理解,创建bean实例,发现传入了beanName,bean定义以及相关的参数用于执行构造函数,跳转到这个方法看一下

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
        // 检查class被load
        Class<?> beanClass = resolveBeanClass(mbd, beanName);
        //检查beanClass
        if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
        }
        //由supplier提供bean实例
        Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
        if (instanceSupplier != null) {
            return obtainFromSupplier(instanceSupplier, beanName);
        }
        //由工厂方法创建bean实例
        if (mbd.getFactoryMethodName() != null) {
            return instantiateUsingFactoryMethod(beanName, mbd, args);
        }

        // 这里表示创建已创建过的bean,判断是通过无参构造函数,还是有参构造函数依赖注入来完成实例化
        boolean resolved = false;
        boolean autowireNecessary = false;
        if (args == null) {
            synchronized (mbd.constructorArgumentLock) {
                if (mbd.resolvedConstructorOrFactoryMethod != null) {
                    resolved = true;
                    autowireNecessary = mbd.constructorArgumentsResolved;
                }
            }
        }
        if (resolved) {
            if (autowireNecessary) {
                return autowireConstructor(beanName, mbd, null, null);
            }
            else {
                return instantiateBean(beanName, mbd);
            }
        }
    
        // 下面是第一次实例化bean的情况,首先判断是否采用有参构造函数
        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
            return autowireConstructor(beanName, mbd, ctors, args);
        }

        // 有参构造函数依赖注入并实例化bean
        ctors = mbd.getPreferredConstructors();
        if (ctors != null) {
            return autowireConstructor(beanName, mbd, ctors, null);
        }

        // 无参构造函数实例化bean
        return instantiateBean(beanName, mbd);
}

三、bean的实例化

其实可以发现,bean最终的实例化无非就是通过无参构造方法或者有参构造方法创建的即通过autowireConstructor方法和instantiateBean方法,由于前者的代码很长,以后有机会会专门写一篇来讲,这次先来看看后者instantiateBean

protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
        try {
            Object beanInstance;
            final BeanFactory parent = this;
            if (System.getSecurityManager() != null) {
                beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
                        getInstantiationStrategy().instantiate(mbd, beanName, parent),
                        getAccessControlContext());
            }
            else {
                beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
            }
            BeanWrapper bw = new BeanWrapperImpl(beanInstance);
            initBeanWrapper(bw);
            return bw;
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
        }
}

不难发现bean是由getInstantiationStrategy().instantiate这一行关键代码实现的,先来看看InstantiationStrategy是何方神圣

public interface InstantiationStrategy {
/**
 * 默认的构造方法
 */
Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner)throws BeansException;

/**
 * 指定构造方法
 */

Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
        Constructor<?> ctor, Object... args) throws BeansException;
        
/**
 * 通过指定的工厂方法
 */
Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
        @Nullable Object factoryBean, Method factoryMethod, Object... args)
        throws BeansException;

简单来说,InitiationStrategy提供了一系列通过构造器来初始化bean实例的策略。

挑选默认的构造方法来看看spring是如何实现的把

public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
    // Don't override the class with CGLIB if no overrides.
    //如果没有方法被覆盖,通过BeanUtils#instantiateClass来初始化(实质是利用反射来创建)
    if (!bd.hasMethodOverrides()) {
        Constructor<?> constructorToUse;
        //加锁
        synchronized (bd.constructorArgumentLock) {
            //获取构造方法constructorToUse
            constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
            if (constructorToUse == null) {
                //获取Bean的class的对象
                final Class<?> clazz = bd.getBeanClass();
                //如果clazz是接口类型的,直接抛BeanInstantiationException异常
                if (clazz.isInterface()) {
                    throw new BeanInstantiationException(clazz, "Specified class is an interface");
                }
                try {
                    //在当前系统安全模式的情况下
                    if (System.getSecurityManager() != null) {
                        constructorToUse = AccessController.doPrivileged(
                                (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
                    }
                    //获取构造方法
                    else {
                        constructorToUse = clazz.getDeclaredConstructor();
                    }
                    //将constructorToUse赋给resolvedConstructorOrFactoryMethod属性
                    bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                }
                catch (Throwable ex) {
                    throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                }
            }
        }
        //通过BeanUtils直接使用构造器对象实例化Bean对象
        return BeanUtils.instantiateClass(constructorToUse);
    }
    else {
        //生成CGLIB创建的子类对象
        return instantiateWithMethodInjection(bd, beanName, owner);
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353