Spring-5.1.5源码解析【IOC】(二)

在上一篇博客内容中,我们已经看了解析 import.alias的源码了,接下来就是bean的这块了:

processBeanDefinition(ele, delegate):

从第一个方法开始看过来,parseBeanDefinitionElement的具体实现:

图没有截全,不过没关系,我们先看这部分,分开来看

1.先获取id与name属性,将name按照分隔符切割为数组,因为我们name可以用逗号分隔来指示多个别名,然后将这个数组添加进一个新创建的集合中,如果id属性为空的话,创建的name集合又不为空,那么将以第一个name为这个bean的id

2.checkNameUniqueness(beanName.aloases,ele):该方法的目的是校验这个id,是否存在所有的bean的id集合中,该集合为一个Set集合,因为要保证id的强一致性(即使A bean的id 与B bean 的name有相同也是不行的,因为bean的name属性也会被添加进这个集合中,如果有定义了多个name,那么第一个值,必须是唯一的,如果在name的数组中还找到了相同的,同样会提示Error)

接着上图往下看:

AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean): 解析bean定义本身,而不考虑名称或别名

AbstractBeanDefinition :具体的BeanDefinition类的基类,分解出GenericBeanDefinition,RootBeanDefinition和ChildBeanDefinition的公共属性

以这里为这个方法的第一步看

this.parseState = ParseState对象

ParseState:基于简单LinkedList的结构,用于跟踪解析过程中的逻辑位置

Entry:在解析阶段的每一点都以特定于读取器的方式添加到LinkedList中。用于ParseState条目的标记接口

BeanEntry:表示bean定义的ParseState条目

之后经量讲明白,尽量少截点图,哈哈哈

接下来来看第二部分:

bd.setResource(this.readerContext.getResource());

bd.setSource(extractSource(ele));

return bd;   (这里是补充)

这里我们来详细看下怎么设置property属性的吧,其他的地方都比较简单,property属性我们也使用的最多了,所以看下实现原理也是有必要滴

parsePropertyElements(ele, bd):

public void parsePropertyElements(Element beanEle, BeanDefinition bd) {

        NodeList nl = beanEle.getChildNodes();

        for (int i = 0; i < nl.getLength(); i++) {

                    Node node = nl.item(i);

                    if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) { //property

                            parsePropertyElement((Element) node, bd);

                    }

        }

}

如果是property标签则进入parsePropertyElement方法:

public void parsePropertyElement(Element ele, BeanDefinition bd) {

           String propertyName = ele.getAttribute(NAME_ATTRIBUTE); // name

           if (!StringUtils.hasLength(propertyName)) {

                    error("Tag 'property' must have a 'name' attribute", ele);

                    return;

            }

            // 添加propertyName条目

            this.parseState.push(new PropertyEntry(propertyName));

            try {

                        //校验该peoperty是否已存在

                        if (bd.getPropertyValues().contains(propertyName)) {

                                error("Multiple 'property' definitions for property '" + propertyName + "'", ele);

                                return;

                        }

                        // 获取属性元素的值 (具体怎么做的在下面可以看得到)

                        Object val = parsePropertyValue(ele, bd, propertyName);

                       // 属性值对象 

                        PropertyValue pv = new PropertyValue(propertyName, val);

                       // 判断是否存在meta标签,有则设置进pv中,因为我们在写配置文件的时候其实是可以往property标签中插入meta标签的

                        parseMetaElements(ele, pv);

                        // 这里啥也没干

                        pv.setSource(extractSource(ele));

                        // 添加进BeanDefinition中

                        bd.getPropertyValues().addPropertyValue(pv);

            } finally {

                        // 这里就不用说了,要不然就显得太罗嗦了

                        this.parseState.pop();

            }

}


Object val = parsePropertyValue(ele, bd, propertyName):获取属性值

1.首先是property的子元素是否只有一个

2.直接贴代码

boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);                     //ref

boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);             //value

// ref和value属性不能一起出现在一个property标签中

if ((hasRefAttribute && hasValueAttribute) || ((hasRefAttribute || hasValueAttribute) && subElement != null)) {

        error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);

}

if (hasRefAttribute) {

        String refName = ele.getAttribute(REF_ATTRIBUTE);

        if (!StringUtils.hasText(refName)) {

                error(elementName + " contains empty 'ref' attribute", ele);

        }

        // RuntimeBeanReference  :不可变占位符类,当属性值对象引用工厂中的另一个bean时,用于在运行时解析它

       RuntimeBeanReference ref = new RuntimeBeanReference(refName);

       // 啥也不干 

       ref.setSource(extractSource(ele));

       return ref;

 }else if (hasValueAttribute) {

        // TypedStringValue:Spring类型字符串值的Holder。可以添加到bean定义中,以便显式地指定字符串值的目标类型,例如集合元素

        // 这个holder只存储字符串值和目标类型。实际的转换将由bean工厂执行。

        TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));

        // 这里也是啥都不干

        valueHolder.setSource(extractSource(ele));

        return valueHolder;

}

PropertyValue:对象来保存单个bean属性的信息和值。在这里使用一个对象,而不是仅仅将所有属性存储在一个按属性名键控的映射中, 这允许更大的灵活性,以及以优化的方式处理索引属性等。

MutablePropertyValues:PropertyValues接口的默认实现,允许对属性进行简单的操作,并提供构造函数来支持映射的深度复制和构造。

然后就没有然后了。就直接返回了,再回到parseBeanDefinitionElement方法中可以发现,下面还有一些对于bean的id为空的情况下的处理,这里我就不说了(时间原因,其实看源码看到这里,接下来的东西也就没啥难度了)

那么就回到parseBeanDefinitionElement方法的最后这一点 :

String[] aliasesArray = StringUtils.toStringArray(aliases);               

return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);

BeanDefinitionHolder:包含名称和别名的bean定义的Holder。可以注册为内部bean的占位符。注册RootBeanDefinition或ChildBeanDefinition就足够了

最后返回的是BeanDefinitionHolder对象.

这里习惯性做个总结吧:

1.如果name属性为空,别名集合不为空,那么将以第一个别名设置为该bean的id

2.验证指定的bean名称和别名在当前bean元素嵌套级别中尚未使用

3.创建GenericBeanDefinition,并且为 GenericBeanDefinition 设置parentName,className

4.设置前置属性(singleton,scope,abstract,default-lazy-init,autowire,depend-on,autowire-candidate,primary,init-method,destroy-method...)

5.判断是否有description标签,如果有则返回

6.判断是否是meta标签,如果存在设置进BeanDefintion

7.判断是否是lookup-method标签,如果存在则添加进覆盖方法列表

8.判断是否是replaced-method标签,如果存在则添加进替换方法列表

9.解析给定bean元素的构造 constructor-arg子元素

10.解析属性元素

11:解析qualifier元素     

12:设置source为XmlBeanDefinitionReader

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {

//BeanDefinitionHolder :包含名称和别名的bean定义的Holder。可以注册为内部bean的占位符。

BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);            // 这里咱们就看完了,接着往下看

        if (bdHolder != null) {

                // 解析我们自定义的属性

                bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

                try {

                        // Register the final decorated instance. // 注册最后修饰后的实例。

                        BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

                } catch (BeanDefinitionStoreException ex) {

                        getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex);

                }

                // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));

        }

}

   bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder):

public BeanDefinitionHolder decorateBeanDefinitionIfRequired( Element ele, BeanDefinitionHolder definitionHolder, @Nullable BeanDefinition containingBd) {

        BeanDefinitionHolder finalDefinition = definitionHolder;

        // 首先基于自定义属性进行装饰

        NamedNodeMap attributes = ele.getAttributes();

        for (int i = 0; i < attributes.getLength(); i++) {

                Node node = attributes.item(i);

                finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);

        }

        // 基于自定义嵌套元素的装饰

        NodeList children = ele.getChildNodes();

        for (int i = 0; i < children.getLength(); i++) {

                Node node = children.item(i);

                if (node.getNodeType() == Node.ELEMENT_NODE) {

                        finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);

                }

        }

        return finalDefinition;

}


BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()) : 注册最后修饰后的实例,将给定的bean定义注册到给定的bean工厂

getReaderContext().getRegistry()  等同于 XmlBeanDefinitionReader.getRegistry() 返回DefaultListableBeanFactory

public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {

        // Register bean definition under primary name.

        String beanName = definitionHolder.getBeanName();

        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());                // 我们主要来看看这个方法是怎么实现的

        // Register aliases for bean name, if any.

        String[] aliases = definitionHolder.getAliases();

        if (aliases != null) {

                for (String alias : aliases){

                    registry.registerAlias(beanName, alias);

                }

        }

}

registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()):

这种太长的方法,我就还是直接贴图把,要不然整理格式都得好久

1.首先是对beanDefinition进行校验(存在覆盖方法并且工厂方法不为空(创建该Bean的工厂方法就不能被覆盖,校验该beanClass是否为Class实例)

2.然后在BeanDefinition缓存中找,目的是为了知道该beanName的beanDefinition是否已经存在,如果存在做另外一种处理,这里我们就不看了

3.判断该beanName是否已经创建过(AbstractBeanFactory中的alreadyCreated:至少创建过一次的bean的名称),如果不为空的话,首先是先把咱们的beanName与BeanDefinition添加进 beanName -> BeanDefinition的缓存中,然后从新初始化bean定义名称列表(beanDefinitionNames集合,也是DefaultListableBeanFactory中的属性,一个List集合),初始化的目的就是为了将我们的beanName添加进集合中,接着如果beanName存在与手动注册的单例程序的名称列表(DefaultListableBeanFactoty中的属性,一个Set集合)中的话,也是从新初始化该集合,不同的是这里是从集合中删除该beanName(如果是存在集合中的话), 初始化(copy-on-write)

4.那就是第三步的else部分了,这里比第三步就直接多了,beanName与BeanDefinition添加进 beanName -> BeanDefinition的缓存中,beanName添加进bean定义名称列表,删除手动注册的单例程序的名称列表中的该beanName

5.最后一步,判断beanDefintion是否存在或者是否已经存在与我们的缓存映射中,如果满足条件则开始清理,我们来把清理的过程和内容记录一下

1.缓存对象的bean的名字:bean名称到bean实例中删除beanName                               DefaultSingletonBeanRegistry.singletonObjects

2.单例工厂的缓存:对象工厂的bean名称中删除beanName                                           DefaultSingletonBeanRegistry.singletonFactories      

3.早期:单例对象缓存的bean bean实例的名字中删除beanName                                  DefaultSingletonBeanRegistry.earlySingletonObjects    

4.注册的单例集合,按注册顺序包含bean名称中删除beanName                                    DefaultSingletonBeanRegistry.registeredSingletons

5.手动注册的单例程序的名称列表,按注册顺序排列(再特么删一次)                              DefaultListableBeanFactory.manualSingletonNames

6.清空单例和非单例bean名称的映射,按依赖项类型键控                                              DefaultListableBeanFactory.allBeanNamesByType         

7.清空单一bean名称的映射,按依赖项类型键控                                                            DefaultListableBeanFactory.singletonBeanNamesByType

到这里registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())就已经结束了,这一步的话其实主要就是将beanName与创建好的BeanDefinition放在缓存中管理起来,回到registerBeanDefinition方法中我们继续往下看

//   为bean名称注册别名(如果有的话) 

String[] aliases = definitionHolder.getAliases();

if (aliases != null) {

    for (String alias : aliases) {

        registry.registerAlias(beanName, alias);

    }

}

registry.registerAlias(beanName, alias): 这个地方我就直接把代码贴上这样方便看,内容也挺简单的,所以就不记录下来了

public void registerAlias(String name, String alias) {

        Assert.hasText(name, "'name' must not be empty");

        Assert.hasText(alias, "'alias' must not be empty");

        synchronized (this.aliasMap) {

                if (alias.equals(name)) {

                        this.aliasMap.remove(alias);

                        if (logger.isDebugEnabled()) {

                                    logger.debug("Alias definition '" + alias + "' ignored since it points to same name");

                        }

               }else{

                        String registeredName = this.aliasMap.get(alias);

                        if (registeredName != null) {

                                if (registeredName.equals(name)) {

                                        return;

                                }

                                if (!allowAliasOverriding()) { // 是否允许别名覆盖。默认值是true;

                                        throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" + name + "': It is already registered for                                         name '" + registeredName + "'.");

                                }

                                if (logger.isDebugEnabled()) {

                                        logger.debug("Overriding alias '" + alias + "' definition for registered name '" + registeredName + "' with new target name                                             '" + name + "'");

                                }

                        }

                        checkForAliasCircle(name, alias); // 检查给定名称是否已经指向另一个方向的给定别名作为别名

                        this.aliasMap.put(alias, name); // 添加进id与alias的映射

                        if (logger.isTraceEnabled()) {

                                logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");

                        }

                }

        }

}

ok了,BeanDefintion跟Aliases都注册了,那么registerBeanDefinition这个方法就完了,就是这样啦,哈哈哈哈,不管里头有多复杂,反正就是特么的两件事,注册我们根据<bean> 创建的BeanDefintion,注册该Bean的别名

那我们再回到processBeanDefinition方法中,还有最后一个方法:,其实最后这个地方都可以不用说了,因为这里其实也还是啥都没干(反正调ReaderContext中那三个属性的方法都是没干活的,哈哈哈哈哈)

getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)) 

是吧,哈哈哈哈

那这里就完了.....就没了,真的没了,然后我们再回到最初的doRegisterBeanDefinitions方法中,我们再看看parseBeanDefinitions(root, this.delegate);下面还有没有其他的方法需要进去看看

parseBeanDefinitions(root, this.delegate);                //这个已经看完了

postProcessXml(root);                                                // 这里不用看,因为下面的实现是空的

this.delegate = parent;

this.delegate = parent: 这里我想我大概弄懂为啥要这样子再赋值一下的意义了,在进入方法的第一步时就把这个delegate 赋值给了parent对象,最后再赋值回来,这说明它想保存当时的状态,但是为啥要这样子搞,我还不清楚

回到parseDefaultElement方法中,目前我们已经把解析import,alias,bean都说了,还有最后一个

else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)){

    // 检查节点名称是否等于beans // recurse

    doRegisterBeanDefinitions(ele);

}

这就不用看了,因为还不是回着头再搞一次,我们本来就是通过doRegisterBeanDefinitions方法进入的嘛 ==



接着再回到AbstractRefreshableApplicationContext:

好了,这里终于看完了

再回到这个最初的方法:

这个地方那就是返回我们上面创建的DefaultListableBeanFactory了 

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 到这里这个方法就算是结束了,做个总结:

1.new  DefaultListableBeanFactory,AbstractBeanFactory中设置parentBeanFactory为ApplicationContext,factoryBean设置唯一标识

2.对ioc容器进行定制化,如设置启动参数,开启注解的自动装配等

3.解析<bean>并且注册BeanDefinition

4.AbstractAutowireCapableBeanFactory的忽略依赖关系接口集合属性中添加了 BeanNameAware,BeanFactoryAware,BeanClassLoaderAware

5.AbstractBeanDefinitionReader中设置resourceLoader 为PathMatchingResourcePatternResolver

6.AbstractBeanDefinitionReader中设置environment 为StandardEnvironment

7.设置XmlBeanDefinitionReader的Environment属性为AbstractApplicationContext中的StandardEnvironment (在我们之前super(parent)这一步的时候给new的)

8.设置XmlBeanDefinitionReader的ResourceLoader为AbstractXmlApplicationContext

9.设置XmlBeanDefinitionReader的EntityResolver为ResourceEntityResolver

10.设置AbstractRefreshableApplicationContext的beanFactory属性为DefaultListableBeanFactory

11.返回DefaultListableBeanFactory


3.prepareBeanFactory(beanFactory):

一个一个来,先从第一个开始

这里我们应该是没有给DefaultResourcceLoader设置过属性的(反正我印象中是没有 ==),那我们就直接看ClassUtils.getDefaultClassLoader()这个方法吧

这个方法很简单吧,先记起来这里是从当前线程中获取classLoader

   下一步 :beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));

先来说说这两个类是啥类:

StandardBeanExpressionResolver:BeanExpressionResolver 接口的标准实现, 使用Spring的表达式模块解析和评估Spring EL

SpelParserConfiguration : SpEL表达式解析器的配置对象

SpelExpressionParser : SpEL 分析器。实例是可重用和线程安全的。

其实这种我们在之前的步骤中也有类似的,只不过在处理这块没这么高大上而已,哈哈哈哈,这里我就不细说是哪个地方了,大家可以自己再从头对着源码看一遍  >_<

我们来写个Demo看看这到底是干嘛的吧,光说的话太不清晰了

有意思的事情就这么发生了

这个可能还不怎么明显,我们再来一种玩法

注意配置文件给换了哦~

我再把这个User类给贴上就知道啥意思了 == 

这下子清晰了吧 == !

我就不介绍太多了,给大家推荐两个地址吧,哈哈哈

http://www.cnblogs.com/longronglang/p/6180023.html      

https://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/expressions.html

下一个:

beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));   //属性编辑器

自定义属性编辑器或注册表以应用于此工厂的bean。

beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)):

ApplicationContextAwareProcessor:该类是BeanPostProcessor接口的实现它是用来处理和回调Aware接口的Bean,不知道大家有没有这样子使用过:

写一个接口继承ApplicationContextAware接口,重写setApplicationContext方法,然后某个实现类,就可以获取到ApplicationContext对象,具体怎么玩,我们还是来写个Demo吧

写个测试接口继承ApplicationContextAware接口

呐~就是这样了

我们来看看这个方法里头是怎么做的:

考虑到安全问题,所以直接是使用CopyOnWriteArrayList这个对象 (不得不说看Spring源码,真的是学到了很多东西)

CopyOnWriteArrayList这个类的介绍给大家推荐一个很不错的地方去看:http://ifeve.com/java-copy-on-write/

1.首先是从集合中删除掉这个对象,这里要说一点注意的就是后置处理器是按照注册的顺序提交的,所以添加的这个元素得是唯一的

2.判断是否是InstantiationAwareBeanPostProcessor接口的实例(InstantiationAwareBeanPostPressor接口可以返回代理对象,例如在创建Bean时,并不都是通过反射来为我们的bean来直接new一个对象的,很多时候都是通过cglib来生成一个代理类,这样做的好处就是更方便Spring来管理这些Bean,例如在Aop的时候,代理类就发挥了很大的作用,这里我们先不细讲,到后面自然就明白了),我们在这里穿的是一个ApplicationContextAwareProcessor对象,所以这里不管

3.判断是否是DestructionAwareBeanPostProcessor接口的实例,这里也不管,因为这里也是走false(eanPostProcessor的子接口,它添加了一个before-destruction回调,销毁bean后置处理器)

4.最后把穿入的beanPostProcessor添加进后置处理器集合中。

来简单看看这个BeanPostProcessor接口吧,看看实现它的作用在哪里.

BeanPostProcessor :

ApplicationContext会自动找到我们实现了BeanPostProcessor接口的所有类,然后把这些类都注册为后置处理器

先贴一张图 == (我写的这篇可能图片,代码贴的比较多,可能不符合很多人的阅读习惯,这里先说声不好意思了,因为我觉得贴图比较亲切 ==。)

直接来写个Demo看看这个实现了这个接口到底能干嘛吧 == 

这里我可是给user设置了name的

这里我可没有设置哟  =_=

呐,就是这样

beanFactory.ignoreDependencyInterface(EnvironmentAware.class);

beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);

beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);

beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);

beanFactory.ignoreDependencyInterface(MessageSourceAware.class);

beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

这里大家应该不陌生,因为在看obtainFreshBeanFactory()该方法的源码时,也做过这种事情 == ,就是往AbstractAutowireCapableBeanFactory中的ignoreDependencyInterfaces Set集合中添加忽略依赖关系类型

beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);

beanFactory.registerResolvableDependency(ResourceLoader.class, this):

beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this):

beanFactory.registerResolvableDependency(ApplicationContext.class, this):

注册具有相应自动获取值的特殊依赖项类型,添加进Default'List'ableBeanFactory的resolvableDependencies集合中

先记下这里是干了这件事

来看看DefaultListableBeanFactory的体系吧

beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)):

检测实现ApplicationListener接口的bean

接着往下:

老规矩一个方法一个个来

先从transformedBeanName(name);这个方法开始

判断我们传递的name是不是以“&”开头的,要是的需要去掉再返回 ,另外我们在配置Bean时,我们是可以配置这个bean的name属性的也就是这个Bean的别名,在canonicalName方法中,我么就是通过别名来找到这个bean的ID,下面就会说到为啥要获取到Bean 的ID

if (containsSingleton(beanName) || containsBeanDefinition(beanName)) {

return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(name));

}

1.首先是在DefaultSingletonBeanRegistry中判断该name是否存在singletonObjects Map属性中(singletonObjects: 缓存对象的bean的名字:bean名称到bean实例)

2.containsBeanDefinition该方法是一个抽象方法,在子类DefaultListableBeanFactory中可以找到该方法实现,该判断是判断在DefaultListableBeanFactory的be'an'DefinitionMap属性中是否存在(beanDefinitionMap: beanName与BeanDefinition对象的映射)

BeanFactory parentBeanFactory = getParentBeanFactory();

return (parentBeanFactory !=null && parentBeanFactory.containsBean(originalBeanName(name)));

我们在看obtainFreshBeanFactory()方法的源码时,在实现中已经给AbstractBeanFactory的parentBeanFactory属性设置了值,而这个值就是一开始我们传入的ApplicationContext,但是ApplicationContext并没有赋值,所以它依然还是null,那么这个方法的返回就是false

总结: beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME) : 检测 loadTimeWeaver是否存在bean实例或BeanDefinition对象

下一个:

if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {

        beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());

}

transformedBeanName这个方法上面已经说了,就不重复了,就直接看看下面是干嘛的吧

(containsSingleton(beanName) || containsBeanDefinition(beanName)) &&

(!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(beanName))

这里也是直接走的false因为初始化时这个bean是既没有实例也没有BeanDefinition的,所以这里我们就快速走完吧,其他的也不细讲了,等源码看到一定程度后,再回过头来把这些看一下写一下,效果可能会更好一点(其实我压根没看过这里的代码),既然上面已经走完了,但是我们在条件里取反,所以来看看如果不存在的情况下是对这个Bean做了什么处理吧

beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());

直接贴实现,哈哈哈哈,我越来越爱直接贴了

这里显示判断是否存在该bean 的实例,不存在则添加,存在则报错,单例嘛

那我们再来看看这个添加的方法

1.该bean添加实例

2. 删除该Bean对应的对象工厂

3.删除该Bean的早期单例对象

4.添加进注册的Bean集合

这里我们来看看假如这里不是空的会发生什么:

synchronized (this.beanDefinitionMap) {

if (!this.beanDefinitionMap.containsKey(beanName)) {

       Set updatedSingletons =new LinkedHashSet<>(this.manualSingletonNames.size() +1);   

      updatedSingletons.addAll(this.manualSingletonNames);

      updatedSingletons.add(beanName);

      this.manualSingletonNames = updatedSingletons;

  }

}else {

   if (!this.beanDefinitionMap.containsKey(beanName)) {

            this.manualSingletonNames.add(beanName);                                        // 手动注册的单例程序的名称列表

     }

}

最后还有一个clearByTypeCache()

getEnvironment()这个就不用说了吧,不用想也知道这是什么飞机,我们最开始就new了一个StandardEnvironment == ,下面两个也不说了,其实都一样了(夜深了,该睡了 == )

到这里prepareBeanFactory方法就算是完了,我们来总结一下吧:

1.从当前Thread中获取类加载器并且设置进beanFactory

2.设置表达式的解析策略

3.设置属性编辑器

4.设置后置处理器

5.添加忽略自动连接的给定依赖接口

6.从依赖项类型映射到相应的对象

            BeanFactory -> DefaultListableBeanFactory

            ResourceLoader -> AbstractApplicationContext

            ApplicationEventPublisher -> AbstractApplicationContext

            ApplicationContext -> AbstractApplicationContext

7.检测实现ApplicationListener接口的bean

8.检测 loadTimeWeaver是否存在bean实例或BeanDefinition对象    

9.检测是否存在 environment/systemProperties/systemEnvironment  的Bean实例与BeanDefinition对象,不存在则添加

还有这么多没写 == 卧槽

感觉已经写的很多很罗嗦了,还是不要都写一块比较好,不过我会尽快把剩下的写完的,哈哈哈哈,感谢大家的阅览!(不早了,该睡了,明天还得上班呢,晚安)

包含名称和别名的bean定义的Holder。可以注册为内部bean的占位符。

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

推荐阅读更多精彩内容