【春のソースコード学習シリーズ】ApplicationContextAwareメソッド呼び出しタイミング

1.背景

実際のビジネス開発では、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.ケース分析

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外側から内側へ

この記事は直接ブレークポイントのデバッグを行います。呼び出しスタックを見てください。

21.jpg

入り口からくしで下ろします。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

22.jpg事前に初期化されたシングルトンBeanに対して実行DefaultListableBeanFactory#preInstantiateSingletons

23.jpg

Bean作成を実行しますAbstractBeanFactory#getBean(java.lang.String)

33.jpgシングルトンBeanを作成するDefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)

24.jpg

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

26.jpgBeanインスタンスを実際に初期化するには:

/**
	 * 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;
	}
	

27.jpgBeanPostProcessorを取得して実行します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;
	}

28.jpg

埋め込む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” 回退到上一层,不断回退。

29.jpg


2.3 从内到外

那么问题又来了,既然执行的是 ApplicationContextAwareProcessor ,那么它又是在哪里创建的呢?

研究之前我们很容易猜出,必定是前面的某个环节构造了这个 ApplicationContextAwareProcessor,到底是哪个环节呢?

继续分析:

35.jpg

跟进去:

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

36.jpg

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);
	}

37.jpg

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);
		beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

		// BeanFactory interface not registered as resolvable type in a plain factory.
		// MessageSource registered (and found for autowiring) as a bean.
		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);

		// Register early post-processor for detecting inner beans as ApplicationListeners.
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

		// Detect a LoadTimeWeaver and prepare for weaving, if found.
		if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			// Set a temporary ClassLoader for type matching.
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}

		// Register default environment beans.
		if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
		}
	}

我们可以看到,它是在我们前面提到的 IOC 容器的最核心的方法 refresh 中的 第 3 步中构造的。

38.jpg

我们可以在上述分析的地方进行断点,验证我们的猜想(省略)。

如在 AbstractBeanFactory#addBeanPostProcessor 处断点,重新运行。

39.jpg 重新运行后果然符合我们的“猜想”:

40.jpg

还有很多问题: (1) 准备 BeanFactory 时还做了哪些事情? (2) BeanNameAware 的方法调用时机又是怎样的? (3)...

三、总结

纸上得来终觉浅,觉知此事需躬行。 希望大家可以参考本文的简单 Demo ,亲自动手调试,理解才能更深刻。

学习贵能举一反三,希望大家能够结合本节所学的方法对第2.3 最后提出的一些问题进行分析。

本文并没有对 IOC容器启动时的最核心方法 AbstractApplicationContext 中的 refresh 进行彻底的剖析,只是结合一个具体案例从某个切面去学习其中的某个环节,大家可以通过更多案例讲整个 refresh 核心方法都串起来,理解会越来越深入。

その上、彼に魚を与えるよりも釣りをするように人に教える方が良いです、方法はより一般的でより価値のあるものです。この記事では、「作者の視点からソースコードを学ぶ」、「最初に推測してから検証する」、「デバッグのための方法論のソースコード」などを伝え、皆様のお役に立てれば幸いです。


作成するのは簡単ではありません。この記事があなたに役立つ場合は、いいね、お気に入り、フォローしてください。あなたのサポートと励ましが私の作成の最大の動機です。

ここに画像の説明を挿入

おすすめ

転載: juejin.im/post/7120656202022780936