Spring中Bean的生命周期源码分析

977 阅读7分钟

前面的梳理中已经将Spring的容器的创建、Bean的创建、BeanPostProcessor的使用、ApplicationListener的使用、代理模式梳理完成,其实以上的所有的梳理都是Spring的Bean声明周期的细节,现在从整体上分析一下Spring中Bean声明周期是如何实现的。

以下的分析会从容器的启动、注解如何加载Bean、创建BeanDefinition、容器的刷新(核心)、创建Bean、销毁Bean的链路梳理,从源头了解Bean的生命周期。

容器启动流程

容器启动流程就是我们平时使用SpringBoot的启动类,在启动类中都会有一段SpringApplication.run(DispatchAdapterApplication.class, args) 代码,这段代码就是启动Spring服务的调用。在这段代码中启动了Spring应用,那么其中又是如何启动Spring容器,并且启动过程中如何将Bean注入到容器中的呢?从源码中梳理整个过程。

容器启动流程:

  1. 创建应用上下文接口ConfigurableApplicationContext,该接口可以理解为是最顶级的接口,该接口中提供了设置Spring环境、设置BeanFactoryPostProcessor、ApplicationListener、注册Bean、销毁Bean的所有方法,该接口是提供给应用启动程序使用,并且主要使用在启动和关闭阶段。
//Spring启动实现类
public class SpringApplication {

    //注解的方式注入类的实现
    public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
    + "annotation.AnnotationConfigApplicationContext";


    
    public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        configureHeadlessProperty();
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                args);
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                                                                     applicationArguments);
            configureIgnoreBeanInfo(environment);
            Banner printedBanner = printBanner(environment);
            //创建AnnotationConfigApplicationContext实现类
            context = createApplicationContext();
            exceptionReporters = getSpringFactoriesInstances(
                SpringBootExceptionReporter.class,
                new Class[] { ConfigurableApplicationContext.class }, context);
            //对AnnotationConfigApplicationContext的准备逻辑,设置环境、监听器等
            prepareContext(context, environment, listeners, applicationArguments,
                           printedBanner);
            //调用容器刷新逻辑
            refreshContext(context);
            //刷新之后的处理,开发者可以重写该方法做后续的处理
            afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass)
                    .logStarted(getApplicationLog(), stopWatch);
            }
            listeners.started(context);
            callRunners(context, applicationArguments);
        }
        .....
        return context;
    }


    protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				switch (this.webApplicationType) {
				case SERVLET:
					contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
					break;
				case REACTIVE:
					contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
					break;
				default:
                    //默认会调用这个实例化AnnotationConfigApplicationContext
					contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
				}
			}
			......
		}
		return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
	}

    private void refreshContext(ConfigurableApplicationContext context) {
        //调用刷新逻辑
		refresh(context);
        
		if (this.registerShutdownHook) {
			try {
                //关闭容器的钩子函数,关闭容器的逻辑中封装了对销毁bean,关闭事件订阅、关闭beanFactory的逻辑
        		//我们一般做服务的优雅上下线就是通过这个钩子函数做的处理
				context.registerShutdownHook();
			}
			.......
		}
	}
}

注解配置类注册流程

  1. 配置应用上下文实现类AnnotationConfigApplicationContext,该类是ConfigurableApplicationContext默认的实现类,从字面意思也可以看到这是一个注解配置的应用上下文实现类,该类可以理解为会扫描所有带**@Configuration** 和**@Component **将带有这些注解的类注入到容器中。
  2. 注解配置应用上下文实现类中会执行scan和register两个逻辑,scan负责扫描所有带有注解的Bean、register负责将这些类解析为BeanDefinition注入到容器中。
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {

    private final AnnotatedBeanDefinitionReader reader;

    private final ClassPathBeanDefinitionScanner scanner;

	//构造函数初始化两个BeanDefinitionReader,分别为AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner
    //分别对应使用注解的加载BeanDefinition和使用xms的加载BeanDefinition
    public AnnotationConfigApplicationContext() {
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }
	
	//功能同上,只不过该构造函数指定了BeanFactory
    public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {
        super(beanFactory);
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

	//初始化自己
    public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
        this();
        //将注解的bean解析到容器中的beanDefinition,所有的bean被初始化为BeanDefinition
        register(annotatedClasses);
        //执行容器的刷新逻辑
        refresh();
    }


    public AnnotationConfigApplicationContext(String... basePackages) {
        this();
        //通过路径扫描所有的bean,然后将bean解析到容器中的beanDefinition
        scan(basePackages);
        //执行容器的刷新逻辑
        refresh();
    }
}

注册BeanDefinition流程

  1. 在AnnotationConfigApplicationContext实现类中register的逻辑就是注册BeanDefinition,将Bean解析为BeanDefinition注册到容器中,用于后续的Bean的创建。
  2. 具体BeanDefinition的创建注入是在DefaultListableBeanFactory中实现的,该实现在BeanDefinition那篇中具体说过。
public class AnnotatedBeanDefinitionReader {
    <T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
			@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {

		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
		if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
			return;
		}

		abd.setInstanceSupplier(instanceSupplier);
		ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
		abd.setScope(scopeMetadata.getScopeName());
		String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

		AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
		if (qualifiers != null) {
			for (Class<? extends Annotation> qualifier : qualifiers) {
				if (Primary.class == qualifier) {
					abd.setPrimary(true);
				}
				else if (Lazy.class == qualifier) {
					abd.setLazyInit(true);
				}
				else {
					abd.addQualifier(new AutowireCandidateQualifier(qualifier));
				}
			}
		}
		for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
			customizer.customize(abd);
		}

		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
	}
}
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
		implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {
    	......
		else {
			if (hasBeanCreationStarted()) {
				// Cannot modify startup-time collection elements anymore (for stable iteration)
				synchronized (this.beanDefinitionMap) {
                    //将BeanDefinition写入到BeanDefinition的容器
					this.beanDefinitionMap.put(beanName, beanDefinition);
					List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;
					if (this.manualSingletonNames.contains(beanName)) {
						Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
						updatedSingletons.remove(beanName);
						this.manualSingletonNames = updatedSingletons;
					}
				}
			}
			else {
				// Still in startup registration phase
				this.beanDefinitionMap.put(beanName, beanDefinition);
				this.beanDefinitionNames.add(beanName);
				this.manualSingletonNames.remove(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}
		......
	}
}

容器刷新流程

  1. BeanDefinition完成注入之后,那么后续就可以提供给容器使用,但是在容器刷新逻辑中还需要完成一些必要的事情,比如BeanPostProcessor、BeanFactoryPostProcessor、ApplicationListener等。开发者定义的这些接口的实现类就是在容器刷新这层实现注入的。
  2. 以BeanPostProcessor为例,开发者实现该接口的实现类,会在该逻辑中注入到指定的ProcessorList中,后续Bean创建时则会遍历ProcessorList执行指定Bean的before和after的增强处理。
public abstract class AbstractApplicationContext extends DefaultResourceLoader
    implements ConfigurableApplicationContext {

        @Override
        public void refresh() throws BeansException, IllegalStateException {
            synchronized (this.startupShutdownMonitor) {
                // 刷新前的处理,比如初始化applicationListeners,初始化配置数据等
                prepareRefresh();

                // 获取前面初始化的beanFactory
                ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

                // 准备beanFactory,向容器中注册一些配置数据,比如ClassLoader、BeanExpressionResolver
                //BeanPostProcessor等等
                prepareBeanFactory(beanFactory);

                try {
                    //允许子类通过该方法对beanFactory做进一步增强
                    postProcessBeanFactory(beanFactory);

                    // 执行beanFactoryPostProcessor的前置和后置处理,类似beanPostProcessor
                    invokeBeanFactoryPostProcessors(beanFactory);

                    // 将实现BeanPostProcessor的增强注册到beanFactory的相关列表中,用于后续执行bean的前置和后置处理逻辑
                    registerBeanPostProcessors(beanFactory);

                    // 初始化 MessageSource,可以做国际化的处理
                    initMessageSource();

                    // 初始化事件分发器,用于后续的的ApplicationEvent的分发
                    initApplicationEventMulticaster();

                    // 初始化一些特殊的子类,如果子类重写了该方法,那么在初始化时会执行重写该方法的子类逻辑,
                    //可以理解为做增强处理
                    onRefresh();

                    // 使用前面初始化的事件分发器,将监听者注册到分发器,用于后续的消息监听
                    registerListeners();

                    // 初始化所有的单例bean(非懒加载的)
                    finishBeanFactoryInitialization(beanFactory);

                    // 完成容器刷新,可以将前面注册的事件通过事件分发器发布事件
                    finishRefresh();
                }catch (BeansException ex) {
                    if (logger.isWarnEnabled()) {
                        logger.warn("Exception encountered during context initialization - " +
                                    "cancelling refresh attempt: " + ex);
                    }
                    // 销毁bean的实现
                    destroyBeans();
                    // 取消刷新,修改容器状态
                    cancelRefresh(ex);
                    throw ex;
                } finally {
                    resetCommonCaches();
                }
        	}
        }
}

创建Bean的流程

  1. 前面所有的准备工作完成之后,那么后续就可以执行Bean的创建,创建Bean的过程中依赖的BeanDefinition、BeanPostProcessor、ApplicationListener等在前面已经完成准备工作,在此时需要实现调用即可。所以前面大部分工作都是为了创建Bean做准备。
  2. 具体的实现如源码所示
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
	protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
		final String beanName = transformedBeanName(name);
		Object bean;
		else {
        	.......省略部分代码
			try {
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);
				// 处理bean的依赖问题,比如循环依赖
				String[] dependsOn = mbd.getDependsOn();
				if (dependsOn != null) {
					for (String dep : dependsOn) {
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						registerDependentBean(dep, beanName);
						try {
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}

				// 判断BeanDefinition是否是单例
				if (mbd.isSingleton()) {
                    //获取单例Bean
					sharedInstance = getSingleton(beanName, () -> {
						try {
                            //创建Bean
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							//如果出现异常则销毁Bean
							destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
				.......
		return (T) bean;
	}

}

销毁Bean的流程

  1. 既然创建了Bean,那么也要对Bean进行销毁,不然Bean一直占用堆内存也会造成影响,因此当服务关闭时在registerShutdownHook中实现了销毁Bean的逻辑。
  2. 在了解Bean在容器中的表现形式之后,知道Bean其实是put到一个map容器中,那么销毁Bean自然而然就是将map中的数据进行remove,有了这个想法,再看源码就会顺利很多。
  3. 追本溯源之后可以看到销毁Bean的最终调用就是将singletonObjects(一级缓存)、singletonFactories(三级缓存)、earlySingletonObjects(二级缓存)、registeredSingletons(缓存BeanName的容器)四个容器中的数据进行remove。所以销毁Bean的逻辑只要了解了Bean的创建,那么销毁自然可以推测出来。
public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext {
	@Override
	public void registerShutdownHook() {
		if (this.shutdownHook == null) {
			// No shutdown hook registered yet.
			this.shutdownHook = new Thread() {
				@Override
				public void run() {
					synchronized (startupShutdownMonitor) {
						doClose();
					}
				}
			};
			Runtime.getRuntime().addShutdownHook(this.shutdownHook);
		}
	}

    protected void destroyBeans() {
		getBeanFactory().destroySingletons();
	}

}
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
	//销毁Bean
	public void destroySingletons() {
		if (logger.isTraceEnabled()) {
			logger.trace("Destroying singletons in " + this);
		}
		synchronized (this.singletonObjects) {
			this.singletonsCurrentlyInDestruction = true;
		}

		String[] disposableBeanNames;
		synchronized (this.disposableBeans) {
			disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
		}
		for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
			destroySingleton(disposableBeanNames[i]);
		}

		this.containedBeanMap.clear();
		this.dependentBeanMap.clear();
		this.dependenciesForBeanMap.clear();

		clearSingletonCache();
	}

    public void destroySingleton(String beanName) {
		// Remove a registered singleton of the given name, if any.
		removeSingleton(beanName);

		// Destroy the corresponding DisposableBean instance.
		DisposableBean disposableBean;
		synchronized (this.disposableBeans) {
			disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
		}
		destroyBean(beanName, disposableBean);
	}
	//清除容器中的Bean
    protected void removeSingleton(String beanName) {
		synchronized (this.singletonObjects) {
			this.singletonObjects.remove(beanName);
			this.singletonFactories.remove(beanName);
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.remove(beanName);
		}
	}
}

总结

从服务的启动到服务的关闭整个流程下来梳理了Bean的整个生命周期,根据这个生命周期自己可以根据这个流程对Spring中容器的实现和Bean的注入流程有了更深的了解,更多细节的部分可以根据一下的源码流程进行debug,毕竟debug看源码是最快的,debug的方式可以知道在每一步入参和出参的结果,以及每一步的正向流程。

  1. org.springframework.boot.SpringApplication#run(java.lang.String...)
  2. org.springframework.boot.SpringApplication#createApplicationContext
  3. org.springframework.context.annotation.AnnotationConfigApplicationContext#AnnotationConfigApplicationContext
  4. org.springframework.context.annotation.AnnotationConfigApplicationContext#register
  5. org.springframework.context.annotation.AnnotatedBeanDefinitionReader#registerBean
  6. org.springframework.context.annotation.AnnotatedBeanDefinitionReader#doRegisterBean
  7. org.springframework.beans.factory.support.BeanDefinitionReaderUtils#registerBeanDefinition
  8. org.springframework.context.support.AbstractApplicationContext#refresh
  9. org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization
  10. org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
  11. org.springframework.beans.factory.support.AbstractBeanFactory#getMergedLocalBeanDefinition
  12. org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)

以上就是自己关于Spring中ApplicationListener的理解,个人能力有限,如有错误,欢迎评论私信指正!共同进步!