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

作者 : 开心源码 本文共19952个字,预计阅读时间需要50分钟 发布时间: 2022-05-12 共206人阅读

接着上一篇没写完的咱们继续,由于实在太长了,我自己看都感觉有点写的太多了,所以就打算分开来写 ==,由于写的比较细,有些地方写点Demo出来也更好了解,所以才导致那么长,由于我也才刚开始看Spring 的源码,写关于Spring源码的初衷并不是说让别人看,而后别人看了之后能学到什么能学到多少,其实更多的是我想把自己看源码的过程给记录下来,一是加深自己的印象,这样更容易了解,一直点方法看的话可能看到主流程就不记得之前是干了啥了,二是方便以后可以重复浏览,当然,假如能给大家看源码带来帮助那是最好不过的事情了,好了,屁话也不多说了直接入正题:

在上一篇博客内容中,我们已经看理解析 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的占位符。

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » Spring-5.1.5源码解析【IOC】(二)

发表回复