[Serie de aprendizaje de código fuente de Spring] Duración de la llamada al método ApplicationContextAware

1. Antecedentes

En el desarrollo comercial real, el ApplicationContext a menudo se obtiene con la ayuda de ApplicationContextAware, y luego se construye la enumeración comercial para el mapeo de patrones de estrategia de procesamiento de beans.

Ver también: "Uso de la inyección automática Spring para realizar la versión mejorada del patrón de estrategia"

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

Entonces, no sé si todos conocen setApplicationContext el momento de la llamada de ? Este artículo analiza con un ejemplo simple. Se recomienda encarecidamente que lo depure usted mismo, y quedará más impresionado.

2. Análisis de casos

2.1 Caso

Definir AwaredTestBeanla ApplicationContextAwareinterfaz de implementación.

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

Escrito basado en anotaciones Configuration:


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

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

}

Construir AnnotationConfigApplicationContextpara probar:

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

Hay muchas maneras de aprender el código fuente, puede consultar mi artículo "¿Cómo aprender y leer el código fuente de manera eficiente?" " , "Cómo leer el código fuente de manera más efectiva: transmisión en vivo" y otros artículos.

El artículo menciona "aprender el código fuente desde el punto de vista del diseñador" y "el método de primero adivinar y luego verificar", por lo que no es difícil para nosotros adivinar que ApplicationContextAware el momento de llamar al método debe ser cuando esté  ApplicationContext listo.

2.2 De afuera hacia adentro

Este artículo directamente la depuración de puntos de interrupción, mira la pila de llamadas.

21.jpg

Peine hacia abajo desde la entrada:AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(java.lang.Class<?>...)

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

El método de actualización aquí es el AbstractApplicationContext#refreshmétodo , que es el método principal cuando se inicia el contenedor 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();
			}
		}
	}

El ApplicationContext inyectado en "11. Inicialice todos los beans singleton restantes (sin carga diferida)", BeanFactory se ha inicializado.AbstractApplicationContext#finishBeanFactoryInitialization

22.jpgEjecutar en bean singleton preinicializadoDefaultListableBeanFactory#preInstantiateSingletons

23.jpg

Ejecutar creación de BeanAbstractBeanFactory#getBean(java.lang.String)

33.jpgCrear un frijol singletonDefaultSingletonBeanRegistry#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.jpgPara inicializar realmente la instancia de 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;
	}
	

27.jpgObtener y ejecutar BeanPostProcessorAbstractAutowireCapableBeanFactory#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

implementarApplicationContextAwareProcessor#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 核心方法都串起来,理解会越来越深入。

Además, es mejor enseñar a un hombre a pescar que darle un pescado, el método es lo más general y lo más valioso. Este artículo intenta transmitir "aprender el código fuente desde el punto de vista del autor", "primero adivinar y luego verificar", "metodología del código fuente para la depuración", etc., con la esperanza de ayudar a todos.


No es fácil de crear. Si este artículo te es útil, dale me gusta, marca como favorito y sígueme. Tu apoyo y aliento son la mayor motivación para mi creación.

inserte la descripción de la imagen aquí

Supongo que te gusta

Origin juejin.im/post/7120656202022780936
Recomendado
Clasificación