zoukankan      html  css  js  c++  java
  • Spring Bean生命周期

    前言

    Spring Bean生命周期是常见的面试题,也是日常开发中经常用到的技术点,在应用开发中,常常需要执行一些特殊的初始化工作,如建立数据库连接,打开网络连接,又比如在一些业务bean里,你想拿到Spring IOC容器,又或者是想拿到一些已经实例化的Bean。同时,在服务结束时,也有一些销毁销毁工作需要执行。为了便于工作的设计,Spring IOC提供相关接口,可以让应用定制Bean的初始化和销毁。

    Spring Bean生命周期

    先来看一下Spring Bean生命周期流程图,方便对照后续的源码分析。
    Spring 生命周期.jpg
    Spring Bean生命周期从大的节点上分为4个过程:实例化、属性赋值、初始化、销毁。 日常业务开发过程中,我们应该涉及最多的两个点就是初始化和销毁,比如自定义Bean实现InitializingBean、DisposeableBean。

    源码分析

    Spring IOC容器初始化

    初始化从AbstractAutowireCapableBeanFactory.doCreateBean方法开始说起,我在对应的代码位置标注了关键点

    protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
    	BeanWrapper instanceWrapper = null;
    	if (mbd.isSingleton()) {
    		instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
    	}
        
    	//1. Bean实例化
    	if (instanceWrapper == null) {
    	   instanceWrapper = this.createBeanInstance(beanName, mbd, args);
    	}
    
    	Object bean = instanceWrapper.getWrappedInstance();
    	Class<?> beanType = instanceWrapper.getWrappedClass();
    	if (beanType != NullBean.class) {
    		mbd.resolvedTargetType = beanType;
    	}
    
    	synchronized(mbd.postProcessingLock) {
    		if (!mbd.postProcessed) {
    			try {
    				this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
    			} catch (Throwable var17) {
    				throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17);
    			}
    
    			mbd.postProcessed = true;
    		}
    	}
    
    	boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
    	if (earlySingletonExposure) {
    		this.addSingletonFactory(beanName, () -> {
    			return this.getEarlyBeanReference(beanName, mbd, bean);
    		});
    	}
    
    	Object exposedObject = bean;
    
    	try {
    	    //2.属性赋值
           this.populateBean(beanName, mbd, instanceWrapper);
    	    //3.初始化
    	    exposedObject = this.initializeBean(beanName, exposedObject, mbd);
    	} catch (Throwable var18) {
    	    if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
    		throw (BeanCreationException)var18;
    	    }
    
    	    throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
    	}
    
    	if (earlySingletonExposure) {
    		Object earlySingletonReference = this.getSingleton(beanName, false);
    		if (earlySingletonReference != null) {
    			if (exposedObject == bean) {
    				exposedObject = earlySingletonReference;
    			} else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {
    				String[] dependentBeans = this.getDependentBeans(beanName);
    				Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length);
    				String[] var12 = dependentBeans;
    				int var13 = dependentBeans.length;
    
    				for(int var14 = 0; var14 < var13; ++var14) {
    					String dependentBean = var12[var14];
    					if (!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
    						actualDependentBeans.add(dependentBean);
    					}
    				}
    
    				if (!actualDependentBeans.isEmpty()) {
    					throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
    				}
    			}
    		}
    	}
    
    	try {
    	    //4.销毁 - 注册回调接口
    	    this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
    	    return exposedObject;
    	} catch (BeanDefinitionValidationException var16) {
    	    throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16);
    	}
    }
    

    为了保持代码片段精简,我删掉了其中的logger代码。

    从以上代码片段里可以看到我们上面总结的Spring生命后期4个关键点都有体现,我们着重分析初始化和销毁流程。

    AbstractAutowireCapableBeanFactory.initializeBean

    protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    	//1.检查Aware相关接口并设置相关依赖
        //BeanNameAware, BeanClassLoaderAware, BeanFactoryAware
    	if (System.getSecurityManager() != null) {
    		AccessController.doPrivileged(() -> {
    			this.invokeAwareMethods(beanName, bean);
    			return null;
    		}, this.getAccessControlContext());
    	} else {
    		this.invokeAwareMethods(beanName, bean);
    	}
    
        //2.BeanPostProcessor前置处理
    	Object wrappedBean = bean;
    	if (mbd == null || !mbd.isSynthetic()) {
    	    //BeanPostProcessor接口的postProcessBeforeInitialization回调
    		wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
    	}
        
    	//3.若实现InitializingBean接口,则调用afterPropertiesSet()
    	//4.若配置自定义的init-method(), 则执行。
    	try {
    		this.invokeInitMethods(beanName, wrappedBean, mbd);
    	} catch (Throwable var6) {
    		throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
    	}
    
        //5.BeanPostProcessor后置处理
    	if (mbd == null || !mbd.isSynthetic()) {
    	    //BeanPostProcessor接口的postProcessAfterInitialization回调
    		wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    	}
    
    	return wrappedBean;
    }
    

    AbstractAutowireCapableBeanFactory.invokeAwareMethods
    invokeAwareMethod就是调用一系列Aware结尾的接口,比如
    BeanNameAware、ApplicationContextAware、BeanFactoryAware。

    private void invokeAwareMethods(String beanName, Object bean) {
       if (bean instanceof Aware) {
          if (bean instanceof BeanNameAware) {
             ((BeanNameAware)bean).setBeanName(beanName);
          }
    
           if (bean instanceof BeanClassLoaderAware) {
               ClassLoader bcl = this.getBeanClassLoader();
               if (bcl != null) {
                   ((BeanClassLoaderAware)bean).setBeanClassLoader(bcl);
               }
           }
    
           if (bean instanceof BeanFactoryAware) {
               ((BeanFactoryAware)bean).setBeanFactory(this);
           }
       }
     }
    

    AbstractAutowireCapableBeanFactory.invokeInitMethods
    invokeinitMethods就是调用InitializingBean接口的afterPropertiesSet,并且检查自定义init-method。

    protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
    	boolean isInitializingBean = bean instanceof InitializingBean;
    	if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
    		if (System.getSecurityManager() != null) {
    			try {
    				AccessController.doPrivileged(() -> {
    					((InitializingBean)bean).afterPropertiesSet();
    					return null;
    				}, this.getAccessControlContext());
    			} catch (PrivilegedActionException var6) {
    				throw var6.getException();
    			}
    		} else {
    			((InitializingBean)bean).afterPropertiesSet();
    		}
    	}
    
    	if (mbd != null && bean.getClass() != NullBean.class) {
    		String initMethodName = mbd.getInitMethodName();
    		if (StringUtils.hasLength(initMethodName) && (!isInitializingBean || !"afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) {
    			this.invokeCustomInitMethod(beanName, bean, mbd);
    		}
    	}
    }
    

    从以上代码片段可以看出Spring IOC容器创建Bean的过程, 涉及的过程包括实例化,销毁,还包括BeanPostProcessor接口相关方法实现,以上代码片段我们分析了Spring容器初始化过程加载Bean的各种实现,下面我们看下Spring容器销毁阶段。

    容器销毁

    Spring容器销毁过程调用链
    Spring 生命周期 Bean销毁 调用链.jpg
    Spring在这里用了适配器模式,也就是说最终的销毁任务由DisposableBeanAdapter来完成,我们看下DisposeableBeanAdapter的结构。
    截屏2021-05-15 09.14.27.png
    从结构中可以看到bean属性类型为Object, 也就是要销毁的Bean,还有beanName属性。

    public void destroy() {
        if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
            Iterator var1 = this.beanPostProcessors.iterator();
    
            while(var1.hasNext()) {
                DestructionAwareBeanPostProcessor processor = (DestructionAwareBeanPostProcessor)var1.next();
                processor.postProcessBeforeDestruction(this.bean, this.beanName);
            }
        }
    
    	if (this.invokeDisposableBean) {
    		try {
    			if (System.getSecurityManager() != null) {
    				AccessController.doPrivileged(() -> {
    					((DisposableBean)this.bean).destroy();
    					return null;
    				}, this.acc);
    			} else {
    				((DisposableBean)this.bean).destroy();
    			}
    		} catch (Throwable var3) {
    			
    		}
    	}
    
    	if (this.destroyMethod != null) {
    		this.invokeCustomDestroyMethod(this.destroyMethod);
    	} else if (this.destroyMethodName != null) {
    		Method methodToInvoke = this.determineDestroyMethod(this.destroyMethodName);
    		if (methodToInvoke != null) {
    			this.invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
    		}
    	}
    }
    

    总结

    Spring Bean生命周期分为4个阶段和多个扩展点,扩展点又分为影响多个Bean和单个Bean。
    4个阶段:实例化、属性赋值、初始化、销毁。
    扩展点
    影响多个Bean

    • BeanPostProcessor
    • InstantiationAwareBeanPostProcessor

    影响单个Bean

    • BeanNameAware
    • BeanFactoryAware
    • BeanClassLoaderAware
    • ApplicationContextAware

    Spring生命周期中两个关键的接口:InitializingBean, DisposableBean。

    博客地址:http://www.cnblogs.com/sword-successful/
    博客版权:本文以学习、研究和分享为主,欢迎转载,但必须在文章页面明显位置给出原文连接。
    如果文中有不妥或者错误的地方还望高手的你指出,以免误人子弟。如果觉得本文对你有所帮助不如【推荐】一下!如果你有更好的建议,不如留言一起讨论,共同进步!
    再次感谢您耐心的读完本篇文章。
  • 相关阅读:
    Python 虚拟环境 virtualenv
    Python
    开发语言之---Java
    LINUX系统
    关系型数据库之MySQL
    开发语言之---Python
    框架之---Django
    递归/面向过程编程
    迭代器/生成器函数及协程函数的编写和使用
    装饰器的编写及使用
  • 原文地址:https://www.cnblogs.com/sword-successful/p/14770835.html
Copyright © 2011-2022 走看看