Spring读源码系列04----bean的加载---上

Posted 大忽悠爱忽悠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring读源码系列04----bean的加载---上相关的知识,希望对你有一定的参考价值。

Spring读源码系列04----bean的加载---上


阅读本系列之前,建议先从本专栏的两个不同视角学习spring的系列作为入门学习点(这两个系列会持续更新),先大体理解spring的架构设计与精髓,然后再来阅读本系列,深入源码分析,而不再纸上谈兵。

从整体来学spring系列文章:

Spring复杂的BeanFactory继承体系该如何理解? ----上

Spring复杂的BeanFactory继承体系该如何理解? ----中

Spring复杂的BeanFactory继承体系该如何理解?—中下

Spring复杂的BeanFactory继承体系该如何理解?—下

Spring复杂的IOC容器之短小的注解篇

Spring繁华的AOP王国—第一讲

Spring繁华的AOP王国—第二讲

Spring繁华的AOP王国—第三讲

Spring繁华的AOP王国----第四讲

Spring繁华的AOP王国—第五讲之应用案例和扩展

该系列持续更新中…


独特视角学习spring系列文章:

不一样的视角来学习Spring源码之容器与Bean—上

不一样的视角来学习Spring源码之容器与Bean—下

不一样的视角来学习Spring源码之AOP—上

不一样的视角来学习Spring源码之AOP—中

不一样的视角来学习Spring源码之AOP—下

该系列持续更新中…


本系列文章:

Spring读源码系列01—Spring核心类及关联性介绍

Spring读源码系列02----默认标签解析过程

Spring读源码系列03----自定义标签解析(待续中)


Bean的加载

    <bean id="peo" class="org.deepSpring.Peo"/>
public class DeepSpringStudy 
    public static void main(String[] args) 
        ClassPathResource classPathResource = new ClassPathResource("bean.xml");
        XmlBeanFactory xmlBeanFactory = new XmlBeanFactory(classPathResource);
        Peo peo = (Peo) xmlBeanFactory.getBean("Peo");
        peo.show();
    


public class XmlBeanFactory extends DefaultListableBeanFactory

正式开始之前,大家心中要有这幅继承图,不然后面会比较懵逼


AbstractBeanFactory#getBean(String name)----根据名字获取bean

AbstractBeanFactory#doGetBean—真正干活的方法

	/**
	 * Return an instance, which may be shared or independent, of the specified bean.
	 */
	@SuppressWarnings("unchecked")
	protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException 
        
        //提取对应的beanName
        //别名到真实的beanName,去掉FactoryBean的&
		String beanName = transformedBeanName(name);
		Object beanInstance;

		//检查缓存中或者实例工厂中是否有对应的实例
		//为什么首先会使用这段代码呢?
		//因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖
		//spring创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光
		//(这里ObjectFactory是啥东西,后面会详细分析)
		//也就是将ObjectFactory加入到缓存中,一旦下个bean创建时候需要依赖上个bean则直接使用ObjectFactory 
        
        //直接尝试从缓存获取或者singletonFactories中的ObjectFactory获取
		Object sharedInstance = getSingleton(beanName);
		//如果从缓存或者对象工厂获取到了对应的实例对象,并且此时构造参数为空--->因为这里必须是无参构造进行创建的
		if (sharedInstance != null && args == null) 
			if (logger.isTraceEnabled()) 
				if (isSingletonCurrentlyInCreation(beanName)) 
					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				
				else 
					logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
				
			
			//getObjectForBeanInstance这个干啥的呢?
			//因为有时候存在诸如BeanFactory的情况,并不是直接返回实例本身而是返回指定方法返回的实例
			beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		
        //如果缓存或者对象工厂中没有的话
		else 
			// Fail if we're already creating this bean instance:
			// We're assumably within a circular reference.
			//只有在单例情况下才会去尝试解决循环依赖,原型模式下,如果存在A中有B的属性,B中有A的属性,那么当依赖注入的时候,就会产生当A还没有创建完的时候因为对于B的创建再次返回创建A,造成循环依赖,也就是下面判断的情况
             
             //isPrototypeCurrentlyInCreation--->返回指定的原型bean当前是否正在创建中
             //其实内部会有一个ThreadLocal<Object> prototypesCurrentlyInCreation属性记录当前线程正在创建的原型bean
			if (isPrototypeCurrentlyInCreation(beanName)) 
				throw new BeanCurrentlyInCreationException(beanName);
			

			// Check if bean definition exists in this factory.
			//获取父容器---这里parentBeanFactory可以在创建BeanFactory通过参数传入
			//如果没有设置,默认为NULL
			BeanFactory parentBeanFactory = getParentBeanFactory();
			//如果存在父容器并且
			//containsBeanDefinition最终调用的是DefaultListableBeanFactory的
			//this.beanDefinitionMap.containsKey(beanName);
			//这个beanDefinitionMap在xml解析过程中每次得到一个BeanDefinition都会往里面注册一个
			//总结:containsBeanDefinition判断当前容器中是否存在beanName对应的BeanDefinition
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) 
			//能进入该判断条件说明在当前容器中找不到,并且又存在父容器,所以尝试去父容器中寻找
				// Not found -> check parent.
				//获取原始的beanName---如果是别名的话,变为别名指向的beanName,如果要获取的是FactoryBean的name的话,也需要进行特殊处理
				String nameToLookup = originalBeanName(name);
				if (parentBeanFactory instanceof AbstractBeanFactory) 
				//去父容器中找---一般都是会继承AbstractBeanFactory
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				
				else if (args != null) 
				//携带构造参数进行查找
					// Delegation to parent with explicit args.
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				
				else if (requiredType != null) 
				//携带参数class类型进行查找
					// No args -> delegate to standard getBean method.
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				
				else 
				//直接按照名字查找
					return (T) parentBeanFactory.getBean(nameToLookup);
				
			
          
            //如果不是仅仅做类型检查则是创建bean,这里要进行记录    
			if (!typeCheckOnly) 
			//将指定的 bean 标记为已创建(或即将创建)。 这允许 bean 工厂优化其缓存以重复创建指定的 bean。
			//这里是用一个Set<String> alreadyCreated集合来存放正在创建中的bean
				markBeanAsCreated(beanName);
			
            
            //我猜测应该是用来追踪状态的 
			StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
					.tag("beanName", name);
			try 
			   //增加追踪信息
				if (requiredType != null) 
					beanCreation.tag("beanType", requiredType::toString);
				
                
                //将存储XML配置文件的GenericBeanDefinition转换为RootBeanDefinition,如果指定beanName是子bean的话,同时还会合并父类的相关属性
                //一会进行分析!!!
				RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);

                 //当前RootBeanDefinition依赖的其他bean   
				// Guarantee initialization of beans that the current bean depends on.
				//解析标签上的depends-on属性时会将解析到的beanName放入到beanDefinition中去
				String[] dependsOn = mbd.getDependsOn();
				//若存在依赖则需要递归实例化依赖的bean
				if (dependsOn != null) 
					for (String dep : dependsOn) 
					//isDependent:如果能从dependentBeanMap集合中找到当前beanName依赖的beans集合,
					//并且该集合包含了当前依赖的dep,说明出现了循环依赖
						if (isDependent(beanName, dep)) 
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						
						//依赖关系注册--->dependenciesForBeanMap
						registerDependentBean(dep, beanName);
						try 
						//递归创建依赖的bean
							getBean(dep);
						
						catch (NoSuchBeanDefinitionException ex) 
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						
					
				

				// Create bean instance.
				//实例化依赖的bean后,便可以实例化mbd本身了
				//singleton模式的创建
				if (mbd.isSingleton()) 
				//getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法一会进行分析
					sharedInstance = getSingleton(beanName, () -> 
						try 
						//这个方法是核心
							return createBean(beanName, mbd, args);
						
						catch (BeansException ex) 
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							destroySingleton(beanName);
							throw ex;
						
					);
					//上面见过一次---如果缓存或者对象工厂有的话
					//因为有时候存在诸如BeanFactory的情况,并不是直接返回实例本身而是返回指定方法返回的实例
					beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				
                 // prototype模式的创建
				else if (mbd.isPrototype()) 
					// It's a prototype -> create a new instance.
					Object prototypeInstance = null;
					try 
					//这里是将当前正在创建中的PrototypeBean放入当前线程的prototypesCurrentlyInCreation--->ThreadLocal<Object>中去
					//一开始当前线程只有一个正在创建的bean时,存放一个string,多余两个时,会变为set集合来存放
					//当前正在创建的PrototypeBeans
						beforePrototypeCreation(beanName);
						//创建!!!----说明是核心方法
						prototypeInstance = createBean(beanName, mbd, args);
					
					finally 
					//将当前bean的创建状态从prototypesCurrentlyInCreation集合中移除掉
						afterPrototypeCreation(beanName);
					
					//因为有时候存在诸如BeanFactory的情况,并不是直接返回实例本身而是返回指定方法返回的实例
					beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				
                 //如果当前bean的作用域不是单例也不是原型,那么进入下面的分支
                 //当然bean为其他类型
				else 
				//在指定的scope上实例化bean
				//获取当前beanDefinition绑定的scopeName 
					String scopeName = mbd.getScope();
					if (!StringUtils.hasLength(scopeName)) 
						throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
					
					//从已注册的scopes集合上获取对应的scope
					Scope scope = this.scopes.get(scopeName);
					if (scope == null) 
						throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
					
					try 
					    //调用scope的get(String name, ObjectFactory<?> objectFactory)方法来返回一个bean实例
					    //objectFactory是一个函数式接口,只有一个getObject方法
						Object scopedInstance = scope.get(beanName, () -> 
						     //同样也是记录当前bean的创建状态
						     //下面记录和移除创建状态的两个方法和Prototype使用的是一样的方法
						     //保存在prototypesCurrentlyInCreation中,对就是和上面Prototype一样的集合
							beforePrototypeCreation(beanName);
							try 
							//无论是什么scope,如果bean还没创建过,都需要调用createBean来创建bean实例对象
								return createBean(beanName, mbd, args);
							
							finally 
							//将当前bean的创建状态从prototypesCurrentlyInCreation集合中移除掉
								afterPrototypeCreation(beanName);
							
						);
						//因为有时候存在诸如BeanFactory的情况,并不是直接返回实例本身而是返回指定方法返回的实例
						beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
					
					catch (IllegalStateException ex) 
						throw new ScopeNotActiveException(beanName, scopeName, ex);
					
				
			
			catch (BeansException ex) 
				beanCreation.tag("exception", ex.getClass().toString());
				beanCreation.tag("message", String.valueOf(ex.getMessage()));
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			
			finally 
				beanCreation.end();
			
		
        //是否需要进行类型转换
		return adaptBeanInstance(name, beanInstance, requiredType);
	






goGetBean方法流程小结



FactoryBean的使用



public interface FactoryBean<T> 
	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

	@Nullable
	T getObject() throws Exception;
	
	@Nullable
	Class<?> getObjectType();
    
    //该方法可以不覆盖,则默认为单例bean
	default boolean isSingleton() 
		return true;
	


举个栗子:

public class MyFactoryBean implements FactoryBean 
    @Override
    public Object getObject() throws Exception 
        return new Bean();
    
    @Override
    public Class<?> getObjectType() 
        return Bean.class;
    
    @Override
    public boolean isSingleton() 
        //原本就是default方法,默认返回true
        return FactoryBean.super.isSingleton();
    

    <bean id="bean" class="org.deepSpring.MyFactoryBean"></bean>

如果希望获取FactoryBean本身,则需要在beanName前面加上&前缀

        xmlBeanFactory.getBean("&bean");

缓存中获取单例bean


让我们回到doGetBean方法的这一行代码来:

		// Eagerly check singleton cache for manually registered singletons.
		Object sharedInstance = getSingleton(beanName);

DefaultSingletonBeanRegistry#getSingleton—尝试从缓存或者ObjectFactory中获取单例bean

	public Object getSingleton(String beanName) 
	//true设置标识允许早期依赖
		return getSingleton(beanName, true);
	
	@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) 
		// Quick check for existing instance without full singleton lock
		//从单例缓冲池中检查缓存中是否存在对应的单例bean实例
		Object singletonObject = this.singletonObjects.get(beanName);
		//如果单例缓冲池中找不到并且当前beanName处于正在创建阶段的话
		//isSingletonCurrentlyInCreation是通过singletonsCurrentlyInCreation集合来判断当前bean是否处于创建状态的
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) 
		//从早期单例对象的缓存获取缓存----这里earlySingletonObjects为什么存在,干啥的,暂时不管,后面进行揭秘
			singletonObject = this.earlySingletonObjects.get(beanName);
			
	    //如果从单例缓冲池和早期单例缓冲池都找不到,并且如果可以创建早期引用###		
			if (singletonObject == null && allowEarlyReference) 
			
				synchronized (this.singletonObjects) 
					// Consistent creation of early reference within full singleton lock
				//这里是单例模式的双重锁校验实现,不知道各位有没有看出来	
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) 
						singletonObject = this.earlySingletonObjects.get(beanName);
						if (singletonObject == null) 
                          
                          //直接看这里就可以了------->
                          //当某些方法需要提前初始化的时候则会调用addSingletonFactory方法将对应的ObjectFactory初始化策略存储在singletonFactories
              

以上是关于Spring读源码系列04----bean的加载---上的主要内容,如果未能解决你的问题,请参考以下文章

Spring源码系列 —— 构造和初始化上下文

Spring读源码系列02----默认标签解析过程

Spring读源码系列01---Spring核心类及关联性介绍

Spring读源码系列07----容器扩展功能--中

Spring读源码系列06----容器扩展功能--上

Spring IOC 源码简单分析 04 - bean的初始化