Spring 源码学习系列ApplicationContextAware#setApplicationContext 方法的调用时机

Posted 明明如月学长

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring 源码学习系列ApplicationContextAware#setApplicationContext 方法的调用时机相关的知识,希望对你有一定的参考价值。

一、背景

在实际业务开发中,经常借助 ApplicationContextAware 获取 ApplicationContext 然后构造业务枚举到处理 Bean 的策略模式映射。

参见:《巧用 Spring 自动注入实现策略模式升级版》

@Service
public class DemoService implements ApplicationContextAware 


    private Map<String, List<Handler>> type2HandlersMap;

    public void test()
      String type ="Vip";
      for(Handler handler : type2HandlersMap.get(type))
          handler.someThing();;
      
    


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException 

        Map<String, Handler> beansOfType = applicationContext.getBeansOfType(Handler.class);
        beansOfType.forEach((k,v)->
            type2HandlersMap = new HashMap<>();
            String type =v.getType();
            type2HandlersMap.putIfAbsent(type,new ArrayList<>());
            type2HandlersMap.get(type).add(v);
        );
    


那么,不知道大家是否都了解 setApplicationContext 的调用时机呢?

本文结合一个简单示例分析一下,这里强烈建议大家自己动手调试一下,印象会更加深刻。

二、案例分析

2.1 案例构造

定义 AwaredTestBean 实现 ApplicationContextAware 接口。

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.stream.Stream;

@Component
public class AwaredTestBean implements ApplicationContextAware 
    private ApplicationContext ctx;

    public void printBeanNames() 
        Stream.of(ctx.getBeanDefinitionNames()).forEach(System.out::println);
    

    @Override
    public void setApplicationContext(ApplicationContext ctx) throws BeansException 
    // 此处断点
        this.ctx = ctx;
    


基于注解编写 Configuration


import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("org.example.aware.bean")
public class AwareConfiguration 



构建 AnnotationConfigApplicationContext 进行测试:

import org.example.aware.bean.AwaredTestBean;
import org.example.aware.config.AwareConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class AwareApplication 

    public static void main(String[] args) throws Exception 
        ApplicationContext ctx = new AnnotationConfigApplicationContext(AwareConfiguration.class);
        AwaredTestBean atBean = ctx.getBean(AwaredTestBean.class);
        atBean.printBeanNames();
    


源码学习的方法有很多,可以参考我的 《如何高效学习和阅读源码?》《如何读源码更有效–直播》 等文章。

文章提到 “以设计者的角度学源码” 和 “先猜想后验证的方法”,因此我们不难猜测,ApplicationContextAware 方法的调用时机 应该是 ApplicationContext 已经准备完毕的时候。

2.2 从外到内

接下来直接断点调试,看调用栈,分析分析。

从入口往下梳理:
AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(java.lang.Class<?>...)

	public AnnotationConfigApplicationContext(Class<?>... componentClasses) 
		this();
		register(componentClasses);
		refresh();
	

这里的 refresh 方法是 AbstractApplicationContext#refresh 方法,是 IOC 容器启动时最核心的方法:

@Override
	public void refresh() throws BeansException, IllegalStateException 
		synchronized (this.startupShutdownMonitor) 
		    // Prepare this context for refreshing.
			//1 初始化前的准备
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			//2 获取 BeanFactory,加载所有 bean 的定义信息(未实例化)
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			// 3 BeanFactory 的预处理配置
			prepareBeanFactory(beanFactory);

			try 
				// Allows post-processing of the bean factory in context subclasses.
				// 4. 准备 BeanFactory 完成后进行的后置处理
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				 // 5. 执行 BeanFactory 创建后的后置处理器
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				// 6. 注册 Bean 的后置处理器
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				// 7. 初始化MessageSource
				initMessageSource();

				// Initialize event multicaster for this context.
				 // 8. 初始化事件派发器
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				 // 9. 子类的多态 onRefresh
				onRefresh();

				// Check for listener beans and register them.
				 // 10. 监听器检查和注册
				registerListeners();
                // ------- BeanFactory已创建完成 --------

				// Instantiate all remaining (non-lazy-init) singletons.
				 // 11. 初始化所有剩下的单例Bean(非懒加载的)
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event. 
				// 12. 完成容器的创建工作(发布相应的事件)
				finishRefresh();
			

			catch (BeansException ex) 
				if (logger.isWarnEnabled()) 
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				

				// Destroy already created singletons to avoid dangling resources.
				// 销毁已经创建的单例避免浪费资源
				destroyBeans();

				// Reset 'active' flag.
				// 重置  active 标记
				cancelRefresh(ex);

				// Propagate exception to caller.
				// 异常抛给调用方
				throw ex;
			

			finally 
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				//13 清理缓存
				resetCommonCaches();
			
		
	

在 “11. 初始化所有剩下的单例Bean(非懒加载的)” 这个环节注入的 ApplicationContext, 此时 BeanFactory 已经初始化完成。
AbstractApplicationContext#finishBeanFactoryInitialization

执行到预初始化单例 bean DefaultListableBeanFactory#preInstantiateSingletons

执行 Bean 的创建 AbstractBeanFactory#getBean(java.lang.String)

创建单例 Bean DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)


AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])

实际初始化 Bean 实例:

/**
	 * Actually create the specified bean. Pre-creation processing has already happened
	 * at this point, e.g. checking @code postProcessBeforeInstantiation callbacks.
	 * <p>Differentiates between default bean instantiation, use of a
	 * factory method, and autowiring a constructor.
	 * @param beanName the name of the bean
	 * @param mbd the merged bean definition for the bean
	 * @param args explicit arguments to use for constructor or factory method invocation
	 * @return a new instance of the bean
	 * @throws BeanCreationException if the bean could not be created
	 * @see #instantiateBean
	 * @see #instantiateUsingFactoryMethod
	 * @see #autowireConstructor
	 */
	protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException 

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) 
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		
		if (instanceWrapper == null) 
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		
		Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) 
			mbd.resolvedTargetType = beanType;
		

		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) 
			if (!mbd.postProcessed) 
				try 
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				
				catch (Throwable ex) 
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				
				mbd.postProcessed = true;
			
		

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) 
			if (logger.isTraceEnabled()) 
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		

		// Initialize the bean instance.
		Object exposedObject = bean;
		try 
		// bean 的属性填充
			populateBean(beanName, mbd, instanceWrapper);
//【重点】执行到这里!!->  初始化 Bean 实例
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		
		catch (Throwable ex) 
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) 
				throw (BeanCreationException) ex;
			
			else 
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			
		

	
	// 省略部分代码

		// Register bean as disposable.
		try 
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		
		catch (BeanDefinitionValidationException ex) 
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		

		return exposedObject;
	
	


获取并执行 BeanPostProcessor AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization

	@Override
	public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
			throws BeansException 

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) 
			Object current = processor.postProcessBeforeInitialization(result, beanName);
			if (current == null) 
				return result;
			
			result = current;
		
		return result;
	

执行 ApplicationContextAwareProcessor#postProcessBeforeInitialization

@Override
	@Nullable
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException 
		if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
				bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
				bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware))
			return bean;
		

		AccessControlContext acc = null;

		if (System.getSecurityManager() != null) 
			acc = this.applicationContext.getBeanFactory().getAccessControlContext();
		

		if (acc != null) 
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> 
				invokeAwareInterfaces(bean);
				return null;
			, acc);
		
		else 
		//【重点】 调用 Aware 接口
			invokeAwareInterfaces(bean);
		

		return bean;
	

调用Bean 实现的 Aware 接口 ApplicationContextAwareProcessor#invokeAwareInterfaces

源码:
	private void invokeAwareInterfaces(Object bean) 
		if (bean instanceof EnvironmentAware) 
			((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
		
		if (bean instanceof EmbeddedValueResolverAware) 
			((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
		
		if (bean instanceof ResourceLoaderAware) 
			((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
		
		if (bean instanceof ApplicationEventPublisherAware) 
			((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
		
		if (bean instanceof MessageSourceAware) 
			((MessageSourceAware) bean).setMessageSource(this.applicationContext);
		
		if (bean instanceof ApplicationContextAware) 
			((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
		
	

从这里可以看到,会判断当前 bean 是否实现了这些 Aware 接口,如果实现了这些接口,那么将 applicationContext 自身 或者 通过 applicationContext 获取所需的参数类型传递过去。


这里顺便说个调试技巧,可以 “Reset Frame” 或者 “Drop Frame” 回退到上一层,不断回退。


2.3 从内到外

那么问题又来了,既然执行的是 ApplicationContextAwareProcessor ,那么它又是在哪里创建的呢?
研究之前我们很容易猜出,必定是前面的某个环节构造了这个 ApplicationContextAwareProcessor,到底是哪个环节呢?

我们继续分析:

跟进去:

public List<BeanPostProcessor> getBeanPostProcessors() 
		return this.beanPostProcessors;
	

AbstractBeanFactory#addBeanPostProcessor:

	@Override
	public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) 
		Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
		// Remove from old position, if any
		this.beanPostProcessors.remove(beanPostProcessor);
		// Track whether it is instantiation/destruction aware
		if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) 
			this.hasInstantiationAwareBeanPostProcessors = true;
		
		if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) 
			this.hasDestructionAwareBeanPostProcessors = true;
		
		// Add to end of list
		this.beanPostProcessors.add(beanPostProcessor);
	

AbstractApplicationContext#prepareBeanFactory:

/**
	 * Configure the factory's standard context characteristics,
	 * such as the context's ClassLoader and post-processors.
	 * @param beanFactory the BeanFactory to configure
	 */
	protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) 
		// Tell the internal bean factory to use the context's class loader etc.
		beanFactory.setBeanClassLoader(getClassLoader());
		beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		// Configure the bean factory with context callbacks.
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
		beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
		beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
		beanFactorySpring读源码系列之AOP--03---aop底层基础类学习

Spring 源码学习系列BeanNameAware#setBeanName 方法的调用时机

Spring读源码系列之AOP--05---aop常用工具类学习

Spring源码深度解析学习系列注册解析的BeanDefinition

Spring 源码学习系列ApplicationContextAware#setApplicationContext 方法的调用时机

Spring 源码学习系列ApplicationContextAware#setApplicationContext 方法的调用时机