La tercera parte de la trilogía de aprendizaje de fuente de inicialización de primavera 4.1.8: AbstractApplicationContext.refresh

Este capítulo es la parte final de la serie "trilogía de aprendizaje de código fuente de inicialización spring4.1.8", que se centra en aprender el método refresh () de la clase AbstractApplicationContext;

Primero revisemos el código de inicialización de la clase ClassPathXmlApplicationContext de la siguiente manera:

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
			throws BeansException {
	super(parent);
	setConfigLocations(configLocations);
	if (refresh) {
		refresh();
	}
}

Los dos primeros de la trilogía aprendieron super (parent) y setConfigLocations (configLocations) :

  1. " Una de la trilogía del aprendizaje del código fuente de inicialización de Spring 4.1.8: método de construcción AbstractApplicationContext ";

  2. " Spring 4.1.8 Trilogía de aprendizaje de fuente de inicialización, segunda parte: método setConfigLocations ";

Introducción al método de actualización

En este capítulo, aprenderemos sobre el método de actualización. El código fuente específico está en la clase AbstractApplicationContext. Para una introducción a este método, vea los comentarios en el siguiente código fuente:

@Override
public void refresh() throws BeansException, IllegalStateException {
	//startupShutdownMonitor对象在spring环境刷新和销毁的时候都会用到,确保刷新和销毁不会同时执行
	synchronized (this.startupShutdownMonitor) {
		// 准备工作,例如记录事件,设置标志,检查环境变量等,并有留给子类扩展的位置,用来将属性加入到applicationContext中
		prepareRefresh();


		// 创建beanFactory,这个对象作为applicationContext的成员变量,可以被applicationContext拿来用,
		// 并且解析资源(例如xml文件),取得bean的定义,放在beanFactory中
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();


		// 对beanFactory做一些设置,例如类加载器、spel解析器、指定bean的某些类型的成员变量对应某些对象等
		prepareBeanFactory(beanFactory);


		try {
			// 子类扩展用,可以设置bean的后置处理器(bean在实例化之后这些后置处理器会执行)
			postProcessBeanFactory(beanFactory);


			// 执行beanFactory后置处理器(有别于bean后置处理器处理bean实例,beanFactory后置处理器处理bean定义)
			invokeBeanFactoryPostProcessors(beanFactory);


			// 将所有的bean的后置处理器排好序,但不会马上用,bean实例化之后会用到
			registerBeanPostProcessors(beanFactory);


			// 初始化国际化服务
			initMessageSource();


			// 创建事件广播器
			initApplicationEventMulticaster();


			// 空方法,留给子类自己实现的,在实例化bean之前做一些ApplicationContext相关的操作
			onRefresh();


			// 注册一部分特殊的事件监听器,剩下的只是准备好名字,留待bean实例化完成后再注册
			registerListeners();


			// 单例模式的bean的实例化、成员变量注入、初始化等工作都在此完成
			finishBeanFactoryInitialization(beanFactory);


			// applicationContext刷新完成后的处理,例如生命周期监听器的回调,广播通知等
			finishRefresh();
		}


		catch (BeansException ex) {
			logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);


			// 刷新失败后的处理,主要是将一些保存环境信息的集合做清理
			destroyBeans();


			// applicationContext是否已经激活的标志,设置为false
			cancelRefresh(ex);


			// Propagate exception to caller.
			throw ex;
		}
	}
}

Luego, analícelo uno por uno:

método prepareRefresh

El código fuente del método prepareRefresh es el siguiente:

protected void prepareRefresh() {
	//记录初始化开始时间
	this.startupDate = System.currentTimeMillis();
	//context是否关闭的标志,设置为false
	this.closed.set(false);
	//context是否激活的标志,设置为true
	this.active.set(true);


	if (logger.isInfoEnabled()) {
		logger.info("Refreshing " + this);
	}


	//留给子类实现的空方法
	initPropertySources();


	/**
	AbstractPropertyResolver类的requiredProperties是个集合,
	在下面的validateRequiredProperties方法中,都要拿requiredProperties中的元素作为key去检查是否存在对应的环境变量,
	如果不存在就抛出异常
	*/
	getEnvironment().validateRequiredProperties();
}

En el código anterior, preste atención a los siguientes dos puntos:

  1. initPropertySources es un método vacío, que se deja en subclases. Tomando la clase AnnotationConfigWebApplicationContext como ejemplo, el método initPropertySources se sobrescribe:

@Override
protected void initPropertySources() {
	ConfigurableEnvironment env = getEnvironment();
	if (env instanceof ConfigurableWebEnvironment) {
		((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, this.servletConfig);
	}
}

Rastreando el método initPropertySources anterior, finalmente encontré WebApplicationContextUtils.initServletPropertySources:

public static void initServletPropertySources(
			MutablePropertySources propertySources, ServletContext servletContext, ServletConfig servletConfig) {


		Assert.notNull(propertySources, "propertySources must not be null");
		if (servletContext != null && propertySources.contains(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME) &&
				propertySources.get(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME) instanceof StubPropertySource) {
			propertySources.replace(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME,
					new ServletContextPropertySource(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME, servletContext));
		}
		if (servletConfig != null && propertySources.contains(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME) &&
				propertySources.get(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME) instanceof StubPropertySource) {
			propertySources.replace(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME,
					new ServletConfigPropertySource(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME, servletConfig));
		}
	}

Lo que hace el código anterior es agregar datos variables de entorno al contexto (los datos provienen de la información de configuración relacionada con el servlet), de modo que el entorno de primavera pueda obtener la variable correspondiente de la clave de contexto en cualquier momento;

  1. El propósito de getEnvironment (). ValidateRequiredProperties () es verificar si existen "algunas" variables en el contexto , ¿qué es "algunas"? Eche un vistazo al método validateRequiredProperties, realice un seguimiento de varias capas de llamadas y finalmente impleméntelo en el método validateRequiredProperties de la clase AbstractPropertyResolver:

@Override
public void validateRequiredProperties() {
	MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
	for (String key : this.requiredProperties) {
		if (this.getProperty(key) == null) {
			ex.addMissingRequiredProperty(key);
		}
	}
	if (!ex.getMissingRequiredProperties().isEmpty()) {
		throw ex;
	}
}

El código anterior muestra que si el nombre en el conjunto requiredProperties no puede encontrar la variable correspondiente en el contexto, se generará una excepción;

Entonces la pregunta es, ¿cuándo se establece la propiedad requiredProperties? No hay ninguna llamada en spring-framework, pero el código fuente oficial de prueba de la unidad nos inspiró, como se muestra a continuación:

Como se muestra en el cuadro rojo anterior, si la empresa necesita asegurarse de que ciertas variables deben existir en el entorno primaveral, puede llamar al método setRequiredProperties para pasar el nombre de la variable, de modo que se verifique el método validateRequiredProperties y podamos implementarlo en función de varios ApplicationContext existentes Personalice una clase de Contexto usted mismo, asegúrese de llamar al método setRequiredProperties antes de llamar al método validateRequiredProperties para pasar el nombre de la variable (por ejemplo, reescribir initPropertySources), puede dejar que Spring complete la inspección por nosotros;

getFreshBeanFactory ()

Luego, mire ConfigurableListableBeanFactory beanFactory = getFreshBeanFactory (); para obtener la variable temporal beanFactory, primero mire la relación entre ConfigurableListableBeanFactory y BeanFactory:

Eche otro vistazo al método getFreshBeanFactory:

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
	//由子类创建beanFactory
	refreshBeanFactory();
	//取得子类创建好的beanFactory,作为obtainFreshBeanFactory方法的返回值返回
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	if (logger.isDebugEnabled()) {
		logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
	}
	return beanFactory;
}

RefreshBeanFactory en algunos de los códigos anteriores necesita una mirada más cercana;

Método refreshBeanFactory

El método refreshBeanFactory es un método abstracto en la clase AbstractApplicationContext. La implementación específica está en una subclase. Tomando su subclase AbstractRefreshableApplicationContext como ejemplo, echemos un vistazo a la implementación del método refreshBeanFactory:

@Override
protected final void refreshBeanFactory() throws BeansException {
	//如果beanFactory已经存在,就销毁context管理的所有bean,并关闭beanFactory
	if (hasBeanFactory()) {
		//其实就是调用一些集合的clear方法,解除对一些实例的引用,参考DefaultSingletonBeanRegistry.destroySingletons方法
		destroyBeans();
		//关闭当前的beanFactory,其实就是将成员变量beanFactory设置为null
		closeBeanFactory();
	}
	try {
		DefaultListableBeanFactory beanFactory = createBeanFactory();
		beanFactory.setSerializationId(getId());
		customizeBeanFactory(beanFactory);
		loadBeanDefinitions(beanFactory);
		synchronized (this.beanFactoryMonitor) {
			this.beanFactory = beanFactory;
		}
	}
	catch (IOException ex) {
		throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
	}
}
  1. El método createBeanFactory en realidad devuelve una instancia de DefaultListableBeanFactory:

protected DefaultListableBeanFactory createBeanFactory() {
	return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
  1. El siguiente método personalizarBeanFactory está reservado para la subclase OverWrite. La descripción y el código fuente del método son los siguientes. La descripción recomienda la configuración especial del beanFactory existente por OverWrite:

/**
* Customize the internal bean factory used by this context.
* Called for each {@link #refresh()} attempt.
* <p>The default implementation applies this context's
* {@linkplain #setAllowBeanDefinitionOverriding "allowBeanDefinitionOverriding"}
* and {@linkplain #setAllowCircularReferences "allowCircularReferences"} settings,
* if specified. Can be overridden in subclasses to customize any of
* {@link DefaultListableBeanFactory}'s settings.
* @param beanFactory the newly created bean factory for this context
* @see DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
* @see DefaultListableBeanFactory#setAllowCircularReferences
* @see DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping
* @see DefaultListableBeanFactory#setAllowEagerClassLoading
*/
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
	if (this.allowBeanDefinitionOverriding != null) {
		//allowBeanDefinitionOverriding表示是否允许注册一个同名的类来覆盖原有类(注意是类,不是实例)
		beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
	}
	if (this.allowCircularReferences != null) {
		//allowCircularReferences表示是否运行多个类之间的循环引用
		beanFactory.setAllowCircularReferences(this.allowCircularReferences);
	}
}
  1. loadBeanDefinitions es un método abstracto en la clase AbstractRefreshableApplicationContext, que está reservada para la implementación de subclase. La función es guardar todas las definiciones de bean en el contexto. Tome AbstractXmlApplicationContext como ejemplo para ver qué hace el método loadBeanDefinitions:

/**
* Loads the bean definitions via an XmlBeanDefinitionReader.
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
* @see #initBeanDefinitionReader
* @see #loadBeanDefinitions
*/
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
	// Create a new XmlBeanDefinitionReader for the given BeanFactory.
	XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);


	// Configure the bean definition reader with this context's
	// resource loading environment.
	beanDefinitionReader.setEnvironment(this.getEnvironment());
	beanDefinitionReader.setResourceLoader(this);
	beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));


	// Allow a subclass to provide custom initialization of the reader,
	// then proceed with actually loading the bean definitions.
	initBeanDefinitionReader(beanDefinitionReader);
	loadBeanDefinitions(beanDefinitionReader);
}

El código anterior muestra que la definición de cargar beans se realiza a través de XmlBeanDefinitionReader, centrándose en el método loadBeanDefinitions:

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
	Resource[] configResources = getConfigResources();
	if (configResources != null) {
		reader.loadBeanDefinitions(configResources);
	}
	String[] configLocations = getConfigLocations();
	if (configLocations != null) {
		reader.loadBeanDefinitions(configLocations);
	}
}

En el código anterior, ¿cuál de getConfigResources () y getConfigLocations () devolverá datos válidos? Esto va a ver el método de construcción de ClassPathXmlApplicationContext:

//这个方法设置的是configLocations 
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
			throws BeansException {


	super(parent);
	setConfigLocations(configLocations);
	if (refresh) {
		refresh();
	}
}


//这个方法设置的是这个方法设置的是configResources 
public ClassPathXmlApplicationContext(String[] paths, Class<?> clazz, ApplicationContext parent)
			throws BeansException {


	super(parent);
	Assert.notNull(paths, "Path array must not be null");
	Assert.notNull(clazz, "Class argument must not be null");
	this.configResources = new Resource[paths.length];
	for (int i = 0; i < paths.length; i++) {
		this.configResources[i] = new ClassPathResource(paths[i], clazz);
	}
	refresh();
}

Por lo tanto, si es configLocations o configResources depende del constructor que usemos para instanciar el objeto applicationContext;

  1. Si la forma en que instanciamos el objeto applicationContext es nuevo ClassPathXmlApplicationContext ("applicationContext.xml") , se llamará al método setConfigLocations, por lo que dentro del método loadBeanDefinitions, el código real ejecutado es el siguiente:

String[] configLocations = getConfigLocations();
	if (configLocations != null) {
		reader.loadBeanDefinitions(configLocations);
	}
  1. Ahora puede ver el método loadBeanDefinitions (String ... ubicaciones) de la clase AbstractBeanDefinitionReader:

public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
		Assert.notNull(locations, "Location array must not be null");
		int counter = 0;
		for (String location : locations) {
			counter += loadBeanDefinitions(location);
		}
		return counter;
	}

Expanda el método llamado en el bucle anterior para:

public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
		ResourceLoader resourceLoader = getResourceLoader();
		if (resourceLoader == null) {
			throw new BeanDefinitionStoreException(
					"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
		}


		if (resourceLoader instanceof ResourcePatternResolver) {
			// Resource pattern matching available.
			try {
				Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
				int loadCount = loadBeanDefinitions(resources);
				if (actualResources != null) {
					for (Resource resource : resources) {
						actualResources.add(resource);
					}
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
				}
				return loadCount;
			}
			catch (IOException ex) {
				throw new BeanDefinitionStoreException(
						"Could not resolve bean definition resource pattern [" + location + "]", ex);
			}
		}
		else {
			// Can only load single resources by absolute URL.
			Resource resource = resourceLoader.getResource(location);
			int loadCount = loadBeanDefinitions(resource);
			if (actualResources != null) {
				actualResources.add(resource);
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
			}
			return loadCount;
		}
	}

En el método anterior, primero recuerde que resourceLoader es ClassPathXmlApplicationContext (beanDefinitionReader.setResourceLoader (this) línea de código), y toda la línea de código resourceLoader.getResource (location) eventualmente llamará al método getResources (String locationPattern) del PathMatchingResourcePatternResolver el objeto relacionado al recurso Después de obtener el objeto Resource, llamará al método loadBeanDefinitions (Resource ... resources) para cargar la definición del bean, y finalmente llamará al método XmlBeanDefinitionReader.loadBeanDefinitions (EncodedResource encodedResource):

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		Assert.notNull(encodedResource, "EncodedResource must not be null");
		if (logger.isInfoEnabled()) {
			logger.info("Loading XML bean definitions from " + encodedResource.getResource());
		}


		Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
		if (currentResources == null) {
			currentResources = new HashSet<EncodedResource>(4);
			this.resourcesCurrentlyBeingLoaded.set(currentResources);
		}
		if (!currentResources.add(encodedResource)) {
			throw new BeanDefinitionStoreException(
					"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
		}
		try {
			InputStream inputStream = encodedResource.getResource().getInputStream();
			try {
				InputSource inputSource = new InputSource(inputStream);
				if (encodedResource.getEncoding() != null) {
					inputSource.setEncoding(encodedResource.getEncoding());
				}
				return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
			}
			finally {
				inputStream.close();
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException(
					"IOException parsing XML document from " + encodedResource.getResource(), ex);
		}
		finally {
			currentResources.remove(encodedResource);
			if (currentResources.isEmpty()) {
				this.resourcesCurrentlyBeingLoaded.remove();
			}
		}
	}

El código anterior muestra que es importante obtener InputStream a través del objeto Resource y luego llamar al método doLoadBeanDefinitions:

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
		try {
			Document doc = doLoadDocument(inputSource, resource);
			return registerBeanDefinitions(doc, resource);
		}
		...

Lo anterior es el código clave para cargar la definición de bean: primero cree el objeto Document, y luego llame al método registerBeanDefinitions, y finalmente coloque la definición de cada bean en el beanDefinitionMap de DefaultListableBeanFactory, la pila detallada es la siguiente:

Después de completar el registro de la definición de bean, puede volver al método AbstractRefreshableApplicationContext.refreshBeanFactory y ver el código después de loadBeanDefinitions (beanFactory):

synchronized (this.beanFactoryMonitor) {
			this.beanFactory = beanFactory;
		}

En este punto, se analiza el método refreshBeanFactory, lo que hace el método: después de analizar la definición del bean en el archivo xml, se almacena en el beanDefinitionMap de DefaultListableBeanFactory;

Ahora, de vuelta al método AbstractApplicationContext.refresh () de la línea principal, hemos analizado el método getFreshBeanFactory (), y todas las definiciones de bean se almacenan en la instancia correspondiente a la variable temporal beanBean;

prepareBeanFactory

Lo siguiente es prepareBeanFactory (beanFactory) , eche un vistazo al código fuente de este método:

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	//设置类加载器
	beanFactory.setBeanClassLoader(getClassLoader());
	//设置解析器,用于解析bean的定义中出现的Spel表达式表达式
	beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
	//设置一个注册接口,该接口只有一个方法registerCustomEditors,用来设置自定义的转换器
	beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));


	// 部署一个bean的后置处理器ApplicationContextAwareProcessor,用于将spring的环境信息注入到实例化的bean之中
	beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
	//bean在初始化的时候,如果有属性的类型为ResourceLoaderAware,则该属性不会被依赖注入
	beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
	beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
	beanFactory.ignoreDependencyInterface(EnvironmentAware.class);


	// BeanFactory interface not registered as resolvable type in a plain factory.
	// MessageSource registered (and found for autowiring) as a bean.
	//bean如果有个属性的类型为BeanFactory.class,那么该属性会被设置为beanFactory
	beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
	beanFactory.registerResolvableDependency(ResourceLoader.class, this);
	beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
	beanFactory.registerResolvableDependency(ApplicationContext.class, this);


	// Detect a LoadTimeWeaver and prepare for weaving, if found.
	if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		// 部署一个bean的后置处理器ApplicationContextAwareProcessor,用于AOP静态代理相关的处理
		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)) {
		//注册一个bean
		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());
	}
}

Los siguientes puntos deben tenerse en cuenta en el código anterior:

  1. beanFactory.addPropertyEditorRegistrar (nuevo ResourceEditorRegistrar (this, getEnvironment ())), este método se debe usar junto con el método AbstractBeanFactory.registerCustomEditors para comprender mejor: el método addPropertyEditorRegistrar coloca un registro en la propiedadEditorRegistrars propiedad, cuando se llama a la propiedad de registro, cuando se usa la propiedad de registro de registro Vaya al registrador en el PropertyEditorRegistrars y llame al método registerCustomEditors de estos registradores para completar la configuración del convertidor personalizado;

  2. El método beanFactory.addBeanPostProcessor se usa para inyectar el postprocesador.Después de crear la instancia de bean, antes y después de ejecutar el método de inicialización, los métodos postProcessBeforeInitialization y postProcessAfterInitialization del postprocesador se llamarán por separado;

  3. beanFactory.ignoreDependencyInterface establece que la interfaz se ignore durante la inyección de dependencia. Por ejemplo, el bean tiene un tipo de propiedad de ResourceLoaderAware, entonces esta propiedad no se inyectará en una instancia del tipo ResourceLoaderAware;

  4. beanFactory.registerResolvableDependency (BeanFactory.class, beanFactory) es una configuración especial. Si un bean tiene un atributo de tipo BeanFactory, el atributo se establecerá en la instancia de beanFactory;

En general, el método prepareBeanFactory es hacer un trabajo de configuración para beanFactory, pasar algunos parámetros y clases de herramientas que se utilizarán más adelante, y luego crear algunos beans en el contenedor de primavera;

postProcessBeanFactory

El método postProcessBeanFactory está reservado para las extensiones de subclase. Puede registrar un postprocesador antes de que se inicialice la instancia de bean (similar a beanFactory.addBeanPostProcessor en el método prepareBeanFactory). Tome la subclase AbstractRefreshableWebApplicationContext como ejemplo. El método postProcessBeanFactory es como sigue:

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
		beanFactory.ignoreDependencyInterface(ServletContextAware.class);
		beanFactory.ignoreDependencyInterface(ServletConfigAware.class);


		WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
		WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
	}

Se puede ver que, excepto por el trabajo de la clase WebApplicationContextUtils, el resto es similar al método prepareBeanFactory;

invokeBeanFactoryPostProcessors

El método invokeBeanFactoryPostProcessors se usa para ejecutar el método postProcessBeanFactory del postprocesador BeanFactoryPostProcessor. Además del postprocesador nativo, también podemos extenderlo nosotros mismos para hacer algunas modificaciones a la definición del Bean, porque el bean no se ha instanciado en este momento. Por lo tanto, no llame a los métodos que desencadenarán la creación de instancias de bean (como el método getBeanNamesForType de BeanFactory) en el BeanFactoryPostProcessor que amplíe. Hay instrucciones relacionadas en la documentación del código fuente, como se muestra en el cuadro rojo a continuación, no active la creación de instancias de bean Procese la instancia de bean en BeanPostProcessor;

registerBeanPostProcessors

El método registerBeanPostProcessors tiene un poco más de código, por lo que no se publica aquí. En pocas palabras, es para encontrar todos los procesadores posteriores del bean (tenga en cuenta que es el procesador posterior del bean, no el procesador posterior de la fábrica bean. El postprocesador se ocupa de las instancias de bean, y el postprocesador de beanfactory se ocupa de las definiciones de bean), y luego los postprocesadores de estos beans se dividen en tres categorías:

  1. Si se implementa la interfaz ordenada Ordered.class, primero se coloca en la colección ordenada de PostProcessors, y luego se agrega a la colección de procesamiento posterior de beanFactory después de la ordenación;

  2. No implementa el procesador posterior Ordered.class ni PriorityOrdered.class, sino que también se une a la colección de procesamiento posterior de beans de la fábrica de frijoles;

  3. Finalmente, se implementa la interfaz de prioridad PriorityOrdered.class. Después de ordenar, el orden se agrega a la colección de postprocesamiento de bean de beanFactory;

Después de la ejecución del método registerBeanPostProcessors, el postprocesador de bean ordenado se ha guardado en beanFactory. Después de instanciar el bean, estos postprocesadores se utilizarán a su vez para realizar el procesamiento correspondiente en la instancia de bean;

initMessageSource

El método initMessageSource se usa para preparar recursos internacionalizados. Almacene el bean que implementa la interfaz MessageSource en la variable miembro de ApplicationContext. Primero, vea si hay una configuración. Si la hay, ejemplifique, de lo contrario, cree un bean de instancia DelegatingMessageSource;

initApplicationEventMulticaster

En primavera, hay eventos, difusores de eventos, escuchas de eventos y otros sistemas de eventos. En el método initApplicationEventMulticaster, se inicializa el difusor de eventos. Si no se puede encontrar la configuración de este bean, se crea una instancia SimpleApplicationEventMulticaster como el bean difusor de eventos, Guardar como una variable miembro applicationEventMulticaster de applicationContext;

onRefresh

onRefresh es un método vacío, que se deja a la subclase para implementar. Antes de instanciar el bean, realice algunas operaciones relacionadas con ApplicationContext. Tomando la subclase AbstractRefreshableWebApplicationContext como ejemplo, eche un vistazo a su método onRefresh:

@Override
protected void onRefresh() {
	this.themeSource = UiApplicationContextUtils.initThemeSource(this);
}

Se puede ver que la inicialización relacionada con el tema se realiza y se guarda en las variables miembro de ApplicationContext;

registrarseListas

El método se llama registerListeners. Parece que el nombre está registrando al oyente en la emisora ​​de eventos, pero este no es el caso. Solo se registran algunos oyentes especiales. Esas clases que implementan la interfaz ApplicationListener en el archivo de configuración de bean no tienen instancias. Entonces, aquí es solo para guardar su nombre en la emisora, la operación de registrar a estos oyentes en la emisora ​​se completa en el procesador posterior del bean, luego se ha instanciado el bean, miramos el código:

protected void registerListeners() {
	// 注册的都是特殊的事件监听器,而并非配置中的bean
	for (ApplicationListener<?> listener : getApplicationListeners()) {
		getApplicationEventMulticaster().addApplicationListener(listener);
	}


	// Do not initialize FactoryBeans here: We need to leave all regular beans
	// uninitialized to let post-processors apply to them!
	// 根据接口类型找出所有监听器的名称
	String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
	for (String listenerBeanName : listenerBeanNames) {
		// 这里只是把监听器的名称保存在广播器中,并没有将这些监听器实例化!!!
		getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
	}
}

finishBeanFactoryInitialization

El método finishBeanFactoryInitialization hace dos cosas:

  1. inicialización de objetos beanFactory;

  2. Los beans singleton que configuramos en el archivo de configuración de bean se instancian en el método finishBeanFactoryInitialization;

Mira el código:

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
	// Initialize conversion service for this context.
	// 实例化类型转换的bean,并保存在ApplicationContext中
	if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
			beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
		beanFactory.setConversionService(
		beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
	}


	// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
	// 实例化LoadTimeWeaverAware接口的bean,用于ApsectJ的类加载期织入的处理
	String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
	for (String weaverAwareName : weaverAwareNames) {
		getBean(weaverAwareName);
	}


	// Stop using the temporary ClassLoader for type matching.
	// 确保临时的classLoader为空,临时classLoader一般被用来做类型匹配的
	beanFactory.setTempClassLoader(null);


	// Allow for caching all bean definition metadata, not expecting further changes.
	// 将一个标志设置为true,表示applicationContext已经缓存了所有bean的定义,这些bean的name都被保存在applicationContext的frozenBeanDefinitionNames成员变量中,相当于一个快照,记录了当前那些bean的定义已经拿到了
	beanFactory.freezeConfiguration();


	// 实例化所有还未实例化的单例bean
	beanFactory.preInstantiateSingletons();
}

En el código anterior, beanFactory.preInstantiateSingletons () necesita expandirse cuidadosamente:

public void preInstantiateSingletons() throws BeansException {
		if (this.logger.isDebugEnabled()) {
			this.logger.debug("Pre-instantiating singletons in " + this);
		}


		// Iterate over a copy to allow for init methods which in turn register new bean definitions.
		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
		List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);


		// Trigger initialization of all non-lazy singleton beans...
		for (String beanName : beanNames) {
			// 获取bean的定义,该定义已经和父类定义做了合并
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			// 非抽象类、是单例、非懒加载
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				//FactoryBean的处理
				if (isFactoryBean(beanName)) {
					final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
					boolean isEagerInit;
					if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
						isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
							@Override
							public Boolean run() {
								return ((SmartFactoryBean<?>) factory).isEagerInit();
							}
						}, getAccessControlContext());
					}
					else {
						isEagerInit = (factory instanceof SmartFactoryBean &&
								((SmartFactoryBean<?>) factory).isEagerInit());
					}
					if (isEagerInit) {
						getBean(beanName);
					}
				}
				else {
					//非FactoryBean的实例化、初始化
					getBean(beanName);
				}
			}
		}


		// Trigger post-initialization callback for all applicable beans...
		// 单例实例化完成后,如果实现了SmartInitializingSingleton接口,afterSingletonsInstantiated就会被调用,此处用到了特权控制逻辑AccessController.doPrivileged
		for (String beanName : beanNames) {
			Object singletonInstance = getSingleton(beanName);
			if (singletonInstance instanceof SmartInitializingSingleton) {
				final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged(new PrivilegedAction<Object>() {
						@Override
						public Object run() {
							smartSingleton.afterSingletonsInstantiated();
							return null;
						}
					}, getAccessControlContext());
				}
				else {
					smartSingleton.afterSingletonsInstantiated();
			}
		}
	}
}

En el código anterior, debemos centrarnos en getBean (beanName), que creará una instancia del bean. Debido a que hay demasiado contenido para elaborar en este capítulo, primero clasificamos la ruta de llamada del bean instanciado:

AbstractBeanFactory.getBean(String name)


->


AbstractBeanFactory.doGetBean(String name, Class<T> requiredType, final Object[] args, boolean typeCheckOnly)


->


DefaultSingletonBeanRegistry.getSingleton(String beanName, ObjectFactory<?> singletonFactory)


->


AbstractBeanFactory.doGetBean中的匿名类的getObject方法


->


AbstractAutowireCapableBeanFactory.createBean(String beanName, RootBeanDefinition mbd, Object[] args) 


->
AbstractAutowireCapableBeanFactory.doCreateBean(final String beanName, final RootBeanDefinition mbd, Object[] args)


->


AbstractAutowireCapableBeanFactory.createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args)


->


instantiateBean(final String beanName, final RootBeanDefinition mbd)


->


SimpleInstantiationStrategy.instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner)


->


BeanUtils.instantiateClass(Constructor<T> ctor, Object... args)


->


Constructor.newInstance(Object ... initargs)


->


bean的构造方法

Se puede ver en la ruta de llamada anterior que la creación del objeto bean se crea por reflexión en el método BeanUtils.instantiateClass;

Echemos un vistazo cuando las variables miembro del bean se inyectan con valores. Como se muestra en la figura siguiente, en el método AbstractAutowireCapableBeanFactory.doCreateBean, primero llame a createBeanInstance para crear el objeto bean (se muestra en el cuadro verde) y luego llame al método populateBean para inyectar contenido en la variable miembro (cuadro rojo) Se muestra):

Escriba una descripción de la imagen aquí

La pila de llamadas del valor inyectado se organiza de la siguiente manera: se puede ver que la inyección también se realiza mediante reflexión:

AbstractAutowireCapableBeanFactory.populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw)


->


AbstractAutowireCapableBeanFactory.applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs)


->


AbstractPropertyAccessor.setPropertyValues(PropertyValues pvs)


->


BeanWrapperImpl.setPropertyValue(PropertyValue pv)


->


Method.invoke(Object obj, Object... args)

Después de leer la lógica de la inyección de la variable miembro, hay otra lógica importante. Preste atención a la inicialización del bean (el atributo init-method en el archivo de configuración del bean). En el método AbstractAutowireCapableBeanFactory.doCreateBean, llame al método populateBean a la variable miembro Inmediatamente después de inyectar el valor, se llama al método initializeBean para la inicialización, y la pila de llamadas se organiza de la siguiente manera:

AbstractAutowireCapableBeanFactory.initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd)


->


AbstractAutowireCapableBeanFactory.invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)


->


AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd)


->


Method.invoke(Object obj, Object... args)

Se puede ver que el método de inicialización todavía se realiza a través de la reflexión;

terminarRefrescar

El último método es finishRefresh, que son algunas operaciones después de que el bean se instancia e inicializa, como devoluciones de llamada para cambios en el ciclo de vida, envío de transmisiones de finalización de actualización de contexto de aplicación, etc., expanda para ver:

protected void finishRefresh() {
	// 检查是否已经配置了生命周期处理器,如果没有就new一个DefaultLifecycleProcessor
	initLifecycleProcessor();


	// 找到所有实现了Lifecycle接口的bean,按照每个bean设置的生命周期阶段进行分组,再依次调用每个分组中每个bean的start方法,完成生命周期监听的通知
	getLifecycleProcessor().onRefresh();


	// 创建一条代表applicationContext刷新完成的事件,交给广播器去广播
	publishEvent(new ContextRefreshedEvent(this));


	// 如果配置了MBeanServer,就完成在MBeanServer上的注册
	LiveBeansView.registerApplicationContext(this);
}

Hasta ahora, hemos pasado todo el proceso de inicialización, pero el espacio es limitado y muchos detalles no se han ampliado. Además, muchas subclases también tienen sus propias extensiones únicas. Todo esto debe tomarse un tiempo para analizarlo detenidamente. Espero que este artículo pueda ayudarlo a organizar ideas de Comprenda los pasos clave de la inicialización en general, para no caer en los detalles prematuramente;

发布了376 篇原创文章 · 获赞 986 · 访问量 128万+

Supongo que te gusta

Origin blog.csdn.net/boling_cavalry/article/details/105463314
Recomendado
Clasificación