spring(三)bean的加载

入门

@Override
    public Object getBean(String name, Object... args) throws BeansException {
        return doGetBean(name, null, args, false);
    }
doGetBean的大概功能如下:
1,提取对应的BeanName
2,检查缓存或者实例工厂的是否有对应的实例
创建bean的时候会有依赖注入的情况,这种情况下为了避免循环依赖,Spring加载的原则是不能bean加载完成,就将bean对应的ObjectFactory放入到缓存中
(提前曝光)
直接尝试从ObjectFactory中获取
3,返回定义的实例,有时候并不是返回实例本身,而是返回指定方法的返回的实例
4,如果已经加载的类不包括BeanName,尝试从父工厂中检测
......

下面是详细介绍
1.转换beanName
2.尝试从缓存中加载单例
3.bean的实例化
4.原型模式的依赖检查
5.检测parentBeanFactory
...

1 FactoryBean的使用

Spring通过反射机制利用bean的class属性来实例化bean,Spring中提供了工厂类的接口,借此来实现实例化bean的逻辑

public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
default boolean isSingleton() {
        return true;
    }
}

摘自书籍

如果bean的实现类是FactoryBean时,通过getBean返回的并不是FactoryBean本身而是getObject()的方法所返回的对象,相当于是getObject()代理了getBean()方法

2 缓存中获取单例的bean

bean的加载,一个bean实例只会被创建一次,第二次获取直接从缓存中获取,如果没有再次从SingletonFactory中获取.
在单例模式下存在的循环依赖问题,解决的方法是:
不等bean加载完成就将bean的ObjectBean放入到缓存中,下次需要使用到这个bean时,直接使用它的ObjectFactory

图片

摘自书籍

3,从bean的实例中获取对象

从缓存中获取到的bean和通过不同的scope中获取到的bean不是最后要使用的bean,我们需要的bean是Factory-method的返回的bean
在使用FactoryBean时,返回的对象时getObject()创建的bean,核心语句为

object = factory.getObject();

4 获取单例

    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(beanName, "Bean name must not be null");
        synchronized (this.singletonObjects) {
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                if (this.singletonsCurrentlyInDestruction) {
                     ....
                beforeSingletonCreation(beanName);
                 .....
                }
                try {
                    singletonObject = singletonFactory.getObject();
                    newSingleton = true;
                }
                ......
                    afterSingletonCreation(beanName);
                }
                if (newSingleton) {
                    addSingleton(beanName, singletonObject);
                }
            }
            return singletonObject;
        }
    }

beforeSingletonCreation(beanName);
singletonObject = singletonFactory.getObject();(核心语言)
afterSingletonCreation(beanName);

5 准备创建bean

    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
        
        try {
            mbdToUse.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
        }

        try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            
        }
    }

prepareMethodOverrides方法如下

    public void prepareMethodOverrides() throws BeanDefinitionValidationException {
        // Check that lookup methods exists.
        if (hasMethodOverrides()) {
            Set<MethodOverride> overrides = getMethodOverrides().getOverrides();
            synchronized (overrides) {
                for (MethodOverride mo : overrides) {
                    prepareMethodOverride(mo);
                }
            }
        }
    }
protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
        int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
        if (count == 0) {
            throw new BeanDefinitionValidationException(
                    "Invalid method override: no method with name '" + mo.getMethodName() +
                    "' on class [" + getBeanClassName() + "]");
        }
        else if (count == 1) {
            // Mark override as not overloaded, to avoid the overhead of arg type checking.
            mo.setOverloaded(false);
        }
    }

相当于是面向切面,当有methodOverWritten,就会为bean创建一个增强

5.2 实例前的处理

try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }

我们进入resolveBeforeInstantiation进行查看

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
        Object bean = null;
        if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
            // Make sure bean class is actually resolved at this point.
            if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
                Class<?> targetType = determineTargetType(beanName, mbd);
                if (targetType != null) {
                    bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                    if (bean != null) {
                        bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                    }
                }
            }
            mbd.beforeInstantiationResolved = (bean != null);
        }
        return bean;
    }

在我们创建bean之前,会进行applyBeanPostProcessorsBeforeInstantiation,applyBeanPostProcessorsAfterInitialization的处理

6.常规的bean的创建

6.1我们对doCreateBean进行分析

instanceWrapper = createBeanInstance(beanName, mbd, args);

(1)如果是单例,先清除缓存
(2)实例化bean,将beanDefinition转换为BeanWrapper
(3)applyMergedBeanDefinitionPostProcessors
(4)依赖的处理

boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isTraceEnabled()) {
                logger.trace("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

(5)填充属性
(6)..
(7)..

6.2创建bean的实例

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
        // Make sure bean class is actually resolved at this point.
        Class<?> beanClass = resolveBeanClass(mbd, beanName);

        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<?> instanceSupplier = mbd.getInstanceSupplier();
        if (instanceSupplier != null) {
            return obtainFromSupplier(instanceSupplier, beanName);
        }

        if (mbd.getFactoryMethodName() != null) {
            return instantiateUsingFactoryMethod(beanName, mbd, args);
        }

        // Shortcut when re-creating the same 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);
            }
        }

        // Candidate constructors for autowiring?
        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
            return autowireConstructor(beanName, mbd, ctors, args);
        }

        // Preferred constructors for default construction?
        ctors = mbd.getPreferredConstructors();
        if (ctors != null) {
            return autowireConstructor(beanName, mbd, ctors, null);
        }

        // No special handling: simply use no-arg constructor.
        return instantiateBean(beanName, mbd);
    }

以上代码的意思如下:摘自书籍
(1),解析class
(2),如果工厂方法不为空,那么通过工厂方法
(3),对于不同的构造函数,要指定它的参数
(4),.......

if (mbd.getFactoryMethodName() != null) {
            return instantiateUsingFactoryMethod(beanName, mbd, args);
        }

6.2.1 autowireConstructor

代码量过多,直接分析功能
(1)构造函数参数的确定
从如下代码中获取,如果explicitArgs 不是空,那么构造函数的参数就是它

if (explicitArgs != null) {
            argsToUse = explicitArgs;
        }

构造函数的参数可能在缓存中,这样可以从缓存中获取
如果以上两种方式都不可能,则执行如下的代码

ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();

(2)构造函数的确定
根据(1)构造函数的参数来确定构造函数
(3)转化构造类型
(4)构造函数不确定的验证
(5)根据实例化策略以及得到的构造函数以及构造函数参数实例化bean

6.2.2 无参构造

6.2.3 实例化策略

用户如果没有使用replace和lookUp的配置方法,那么直接使用反射的方式,简单快捷,如果有的话,那就需要使用动态代理的方式将增强设置进去

6.3 记录创建bean 的ObjectFactory

我们来看如下代码

boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));

是否是单例
是否是循环依赖
是否已经在创建中
当以上三个条件都满足时,我们执行如下的代码

if (earlySingletonExposure) {
            if (logger.isTraceEnabled()) {
                logger.trace("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

我们重点看一下addSingletonFactory这个方法

    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

其中调用了getEarlyBeanReference这个方法,我们在进入这个方法一探究竟
我们关注的是B在填充属性时,不是递归调用,而是使用getBean方法,其意思是指直接调用ObjectFactory来创建A,但B持有的A是没有任何属性的A

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;
    }
解决循环依赖

6.4 属性注入

我们来看第一个方法autoWireByName,具体功能就是通过value找到已经加载的bean,并递归实例化,然后在放入其中,然后在来看autoWireByType,查看需要注入的属性,遍历这些属性找到与其相配的bean
这时候就获取到了所有的注入属性

if (pvs != null) {
            applyPropertyValues(beanName, mbd, bw, pvs);
        }
通过这个方法,就可以将属性应用到bean中

6.5 初始化bean

执行初始化之前,已经完成了属性的填充,以及实例化

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,864评论 6 494
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,175评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,401评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,170评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,276评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,364评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,401评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,179评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,604评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,902评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,070评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,751评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,380评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,077评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,312评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,924评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,957评论 2 351

推荐阅读更多精彩内容