Spring 5.x 源码之旅-14isFactoryBean方法解读

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

学习必须往深处挖,挖的越深,基础越扎实!

阶段1、深入多线程

阶段2、深入多线程设计模式

阶段3、深入juc源码解析


阶段4、深入jdk其余源码解析


阶段5、深入jvm源码解析

码哥源码部分

码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】

码哥讲源码【炸雷啦!炸雷啦!黄光头他终于跑路啦!】

码哥讲源码-【jvm课程前置知识及c/c++调试环境搭建】

​​​​​​码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】

码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】

码哥讲源码【你水不是你的错,但是你胡说八道就是你不对了!】

码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】

终结B站没人能讲清楚红黑树的历史,不服等你来踢馆!

打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】

isFactoryBean(String name)根据名字判断是否是FactoryBean

我们继续上篇,上篇讲了getMergedLocalBeanDefinition,以及为什么要用这个,本篇来讲后面的isFactoryBean方法,怎么来判断一个beanName是否是FactoryBean类型。getBean比较复杂,后面一起讲,暂时知道这个可以获取对象就好,本篇讲这部分:

    @Override
    	public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {
    		String beanName = transformedBeanName(name);//获取转换后的名字
    		Object beanInstance = getSingleton(beanName, false);
    		if (beanInstance != null) {//如果已经是单例了,就判断是否是FactoryBean类型
    			return (beanInstance instanceof FactoryBean);
    		}
    		// 没有单例,看是否有bean定义,没有就看父类bean工厂
    		if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {			
    			return ((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name);
    		}
    		return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
    	}

transformedBeanName转换后的名字

我们来看这个转换名字,其实跟上篇说的FactoryBean名字相关,我们还是来看源码吧:

    	protected String transformedBeanName(String name) {
    		return canonicalName(BeanFactoryUtils.transformedBeanName(name));
    	}

BeanFactoryUtils的transformedBeanName

首先判断是不是有&前缀,没有就直接返回,说明不是FactoryBean的名字,否则就从缓存里获取,然后把前缀&去掉返回。

    public static String transformedBeanName(String name) {
    		Assert.notNull(name, "'name' must not be null");
    		if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
    			return name;
    		}
    		return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
    			do {
    				beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
    			}
    			while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
    			return beanName;
    		});
    	}

canonicalName取出原始名字

进行名字的规范化,其实就是取出原始名字,如果是别名就从映射中取原始名,是原始名字直接返回。

    public String canonicalName(String name) {
    		String canonicalName = name;
    		// Handle aliasing...
    		String resolvedName;
    		do {
    			resolvedName = this.aliasMap.get(canonicalName);
    			if (resolvedName != null) {
    				canonicalName = resolvedName;
    			}
    		}
    		while (resolvedName != null);
    		return canonicalName;
    	}

getSingleton(String beanName, boolean allowEarlyReference)获取单例

这个方法传入一个名字和是否允许早期引用,这个是为了解决循环依赖的问题,这个后面会讲,现在忽略就行。singletonObjects是一个ConcurrentHashMap,放已经创建好的单例,如果发现有创建好了,就直接返回,否则判断是否正在创建isSingletonCurrentlyInCreationearlySingletonObjectsHashMap,用来保存运行早期创建引用的单例,为了解决循环依赖。我们可能会奇怪,为什么earlySingletonObjects不是ConcurrentHashMap,其实因为他所有的操作,都是在synchronized 同步块中了,所以不需要了,而singletonObjects则可以在没有同步块的地方使用。继续说,如果在earlySingletonObjects也没找到,又是允许早期引用的,就从单例singletonFactories工厂中获取一个工厂,其实就是一个可以获取对象的工厂,只要存在,就能通过getObject()获取,然后放进earlySingletonObjects,删除工厂,其实有循环引用的时候就可以派上用了,后面会说。

    @Nullable
    	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    		Object singletonObject = this.singletonObjects.get(beanName);
    		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    			synchronized (this.singletonObjects) {
    				singletonObject = this.earlySingletonObjects.get(beanName);
    				if (singletonObject == null && allowEarlyReference) {
    					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
    					if (singletonFactory != null) {
    						singletonObject = singletonFactory.getObject();
    						this.earlySingletonObjects.put(beanName, singletonObject);
    						this.singletonFactories.remove(beanName);
    					}
    				}
    			}
    		}
    		return singletonObject;
    	}

isSingletonCurrentlyInCreation是否正在创建中

singletonsCurrentlyInCreation这个是个set存放正在创建的单例的名字,所以可以判断是否正在创建中。

    	public boolean isSingletonCurrentlyInCreation(String beanName) {
    		return this.singletonsCurrentlyInCreation.contains(beanName);
    	}

isFactoryBean(String beanName, RootBeanDefinition mbd)根据名字和bean定义判断是否是FactoryBean

如果FactoryBean单例没获取到,此时只能通过名字和bean定义看是否是FactoryBean了。如果定义本身定义了isFactoryBean,那就直接返回结果,否则需要进行类型预测,他会进行反射,看看名字对应的类是否是FactoryBean类型的,如果预测出来的类型是FactoryBean,那就返回true了,否则就false

    protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {
    		Boolean result = mbd.isFactoryBean;
    		if (result == null) {
    			Class<?> beanType = predictBeanType(beanName, mbd, FactoryBean.class);
    			result = (beanType != null && FactoryBean.class.isAssignableFrom(beanType));
    			mbd.isFactoryBean = result;
    		}
    		return result;
    	}

获取FactoryBean

如果发现名字是FactoryBean类型的话,就会在名字前加前缀&,然后去获取,获取完了判断是否是FactoryBean类型,是的话再判断是否需要理解创建FactoryBean中的对象,如果是的话就直接获取名字,此时的名字是没有&前缀的,也就直接获取FactoryBeangetObject()方法创建的对象。当然如果名字不是FactoryBean类型的话,就直接获取对象。

总结

这部分主要就是创建单例,如果发现是FactoryBean类型的话,就获取FactoryBean,然后判断是否需要立即进行getObject()方法创建的对象,需要的话就创建。如果不是FactoryBean类型的话,就直接获取创建对象。

  • 9
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值