springapplicationcontext启动过程(代码片段)

ac_dao_di ac_dao_di     2022-12-05     696

关键词:

1. 前言

    spring boot 2.1.7启动过程源码解析讲到了SpringBoot的启动过程,在第5模块和第6模块,讲到了Spring ApplicationContext的启动过程,会创建一个AnnotationConfigServletWebServerApplicationContext,之后调用相关的ApplicationContextInitializer对其进行初始化,包括设置parent context、加载远程property构建environment等,之后注册main方法所在类,作为启动配置的第一个类,进而加载所有的业务bean。本文对第5模块和第6模块,进行更加详细的剖析。

    本文源码见:源码

    一张图总结spring ApplicationContext启动过程整个启动过程

2. 注册基本的注解后处理器

    在SpringApplication.prepareContext方法中,会构建一个BeanDefinitionLoader,该类的构造方法在初始化的过程中,会注入常见的注解后处理器。由于AnnotationConfigServletWebServerApplicationContext继承自GenericApplicationContext,在构造函数初始化时,就已经构建了beanFactory,且类型为DefaultListableBeanFactory。所以可以添加后处理器和注册bean

	BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) 
		Assert.notNull(registry, "Registry must not be null");
		Assert.notEmpty(sources, "Sources must not be empty");
		this.sources = sources;
		// 构建AnnotatedBeanDefinitionReader
		this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
		this.xmlReader = (XML_ENABLED ? new XmlBeanDefinitionReader(registry) : null);
		this.groovyReader = (isGroovyPresent() ? new GroovyBeanDefinitionReader(registry) : null);
		this.scanner = new ClassPathBeanDefinitionScanner(registry);
		this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
	
	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) 
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		Assert.notNull(environment, "Environment must not be null");
		this.registry = registry;
		this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
		// 注入常见的后处理器
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
	

    如下,总共会注入5个处理器

  • ConfigurationClassPostProcessor
        主要处理@Component注解配置,注入beanDefinition

  • AutowiredAnnotationBeanPostProcessor
        主要处理bean属性上和方法上的@Autowired/@Value,注入依赖。

  • CommonAnnotationBeanPostProcessor
        主要处理bean属性上的@Resource,注入依赖。

  • EventListenerMethodProcessor
        主要处理bean方法上的@EventListener,注册为ApplicationListener,添加到ApplicationContext中。

  • DefaultEventListenerFactory

	public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) 

		DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
		if (beanFactory != null) 
			if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) 
				beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
			
			if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) 
				beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
			
		

		Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

		if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) 
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
		

		if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) 
			RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
		

		// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
		if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) 
			RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
		

		// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
		if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) 
			RootBeanDefinition def = new RootBeanDefinition();
			try 
				def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
						AnnotationConfigUtils.class.getClassLoader()));
			
			catch (ClassNotFoundException ex) 
				throw new IllegalStateException(
						"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
			
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
		

		if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) 
			RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
		

		if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) 
			RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
		

		return beanDefs;
	

3. 注册main方法所在类

    当调用BeanDefinitionLoader.load时,会将main方法所在类注册到BeanDefinitionRegistry,也就是当前AnnotationConfigServletWebServerApplicationContext。

4. 刷新上下文

// org.springframework.context.support.AbstractApplicationContext#refresh
	@Override
	public void refresh() throws BeansException, IllegalStateException 
		synchronized (this.startupShutdownMonitor) 
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			// (1) 构建beanFactory,load bean definition等等
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try 
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);
				beanPostProcess.end();

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				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.
				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...
				resetCommonCaches();
				contextRefresh.end();
			
		
	

4.1 获取刷新BeanFactory

    obtainFreshBeanFactory分为两步,先刷新,再后取。在AbstractApplicationContext定义好了这两个抽象方法。

//org.springframework.context.support.AbstractApplicationContext#obtainFreshBeanFactory
	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() 
		refreshBeanFactory();
		return getBeanFactory();
	
	protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;

	protected abstract void closeBeanFactory();

	@Override
	public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;

    实现类有两个,一个是可刷新的,需要在子类中实现loadBeanDefinitions方法,一般是加载类型比较确定的,例如xml/config等,一般是在调用refresh后,才有getBeanFactory才非空。org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory;

4.1.1 可重复构建BeanFactory

    可刷新的ApplicationContext,需要在子类中实现loadBeanDefinitions方法,一般是加载类型比较确定的,例如xml/config等,一般是在调用refresh后,才有getBeanFactory才非空。org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory;

	@Override
	protected final void refreshBeanFactory() throws BeansException 
		if (hasBeanFactory()) 
			destroyBeans();
			closeBeanFactory();
		
		try 
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
			// 核心
			loadBeanDefinitions(beanFactory);
			this.beanFactory = beanFactory;
		
		catch (IOException ex) 
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		
	
@Override
	public final ConfigurableListableBeanFactory getBeanFactory() 
		DefaultListableBeanFactory beanFactory = this.beanFactory;
		if (beanFactory == null) 
			throw new IllegalStateException("BeanFactory not initialized or already closed - " +
					"call 'refresh' before accessing beans via the ApplicationContext");
		
		return beanFactory;
	

    对应的子类有,loadBeanDefinitions如何实现?

    AbstractXmlApplicationContext,需要子类设置configLocations等配置文件。

// org.springframework.context.support.AbstractXmlApplicationContext
	/**
	 * 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);
	

	/**
	 * Initialize the bean definition reader used for loading the bean
	 * definitions of this context. Default implementation is empty.
	 * <p>Can be overridden in subclasses, e.g. for turning off XML validation
	 * or using a different XmlBeanDefinitionParser implementation.
	 * @param reader the bean definition reader used by this context
	 * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader#setDocumentReaderClass
	 */
	protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) 
		reader.setValidating(this.validating);
	

	/**
	 * Load the bean definitions with the given XmlBeanDefinitionReader.
	 * <p>The lifecycle of the bean factory is handled by the @link #refreshBeanFactory
	 * method; hence this method is just supposed to load and/or register bean definitions.
	 * @param reader the XmlBeanDefinitionReader to use
	 * @throws BeansException in case of bean registration errors
	 * @throws IOException if the required XML document isn't found
	 * @see #refreshBeanFactory
	 * @see #getConfigLocations
	 * @see #getResources
	 * @see #getResourcePatternResolver
	 */
	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);
		
	

    AnnotationConfigWebApplicationContext,需要子类设置basePackages等包路径,也可以设置componentClasses

	@Override
	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) 
		AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
		ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);

		BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
		if (beanNameGenerator != null) 
			reader.setBeanNameGenerator(beanNameGenerator);
			scanner.setBeanNameGenerator(beanNameGenerator);
			beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
		

		ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
		if (scopeMetadataResolver != null) 
			reader.setScopeMetadataResolver(scopeMetadataResolver);
			scanner.setScopeMetadataResolver(scopeMetadataResolver);
		

		if (!this.componentClasses.isEmpty()) 
			if (logger.isDebugEnabled()) 
				logger.debug("Registering component classes: [" +
						StringUtils.collectionToCommaDelimitedString(this.componentClasses) + "]");
			
			reader.register(ClassUtils.toClassArray(this.componentClasses));
		

		if (!this.basePackages.isEmpty()) 
			if (logger.isDebugEnabled()) 
				logger.debug("Scanning base packages: [" +
						StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");
			
			scanner.scan(StringUtils.toStringArray(this.basePackages));
		

		String[] configLocations = getConfigLocations();
		if (configLocations != null) 
			for (String configLocation : configLocations) 
				try 
					Class<?> clazz = ClassUtils.forName(configLocation, getClassLoader());
					if (logger.isTraceEnabled()) 
						logger.trace("Registering [" + configLocation + "]");
					
					reader.register(clazz);
				
				catch (ClassNotFoundException ex) 
					if (logger.isTraceEnabled()) 
						logger.trace("Could not load class for config location [" + configLocation +
								"] - trying package scan. " + ex);
					
					int count = scanner.scan(configLocation);
					if (count == 0 && logger.isDebugEnabled()) 
						logger.debug("No component classes found for specified class/package [" + configLocation + "]");
					
				
			
		
	

4.1.2 不可重复构建BeanFactory

    一个是不能刷新的,在构造函数时,已经就构建了BeanFactory。org.springframework.context.support.GenericApplicationContext#refreshBeanFactory。

	@Override
	protected final void refreshBeanFactory() throws IllegalStateException 
		if (!this.refreshed.compareAndSet(false, true)) 
			throw new IllegalStateException(
					"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
		
		this.beanFactory.setSerializationId(getId());
	
	
	@Override
	public final ConfigurableListableBeanFactory getBeanFactory() 
		return this.beanFactory;
	

    GenericApplicationContext主要的子类如下,SpringBoot使用的AnnotationConfigServletWebServerApplicationContext该子类之一。所以这里其实刷新也没什么实际逻辑,就是设置了序列化id,而且有刷新标识,只能调用一次。

 事实上,默认springBoot的所有ApplicationContext均是GenericApplicationContext的子类:

// org.springframework.boot.ApplicationContextFactory
	ApplicationContextFactory DEFAULT = (webApplicationType) -> 
		try 
			switch (webApplicationType) 
			case SERVLET:
				return new AnnotationConfigServletWebServerApplicationContext();
			case REACTIVE:
				return new AnnotationConfigReactiveWebServerApplicationContext();
			default:
				return new AnnotationConfigApplicationContext();
			
		
		catch (Exception ex) 
			throw new IllegalStateException("Unable create a default ApplicationContext instance, "
					+ "you may need a custom ApplicationContextFactory", ex);
		
	;

4.2 prepareBeanFactory

    这一步,主要是对BeanFactory进行配置,设置ApplicationContextAwareProcessor,注入一些常见的依赖解析,包括beanFactory,ApplicationContext,ResourceLoader、Environment等。

	protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) 
		// Tell the internal bean factory to use the context's class loader etc.
		beanFactory.setBeanClassLoader(getClassLoader());
		if (!shouldIgnoreSpel) 
			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.ignoreDependencyInterface(ApplicationStartupAware.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 (!NativeDetector.inNativeImage() && 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());
		
		if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) 
			beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
		

    其中ApplicationContextAwareProcessor

class ApplicationContextAwareProcessor implements BeanPostProcessor 
    @Override
	@Nullable
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException 
		invokeAwareInterfaces(bean);
		return bean;
	

	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 ApplicationStartupAware) 
			((ApplicationStartupAware) bean).setApplicationStartup(this.applicationContext.getApplicationStartup());
		
		if (bean instanceof ApplicationContextAware) 
			((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
		
	


4.3 postProcessBeanFactory

    主要是注入WebApplicationContextServletContextAwareProcessor,支持ServletContextAware/ServletConfigAware,之后扫描basePackages,注册注解类,但是这后面两步一般都是空操作。

// 父类:org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#postProcessBeanFactory
/**
	 * Register ServletContextAwareProcessor.
	 * @see ServletContextAwareProcessor
	 */
	@Override
	protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) 
		beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));
		beanFactory.ignoreDependencyInterface(ServletContextAware.class);
		registerWebApplicationScopes();
	
// 子类:org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext#postProcessBeanFactory
	@Override
	protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) 
		super.postProcessBeanFactory(beanFactory);
		if (this.basePackages != null && this.basePackages.length > 0) 
			this.scanner.scan(this.basePackages);
		
		if (!this.annotatedClasses.isEmpty()) 
			this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
		
	

4.4 invokeBeanFactoryPostProcessors

    主要是使用BeanFactoryPostProcessor对BeanFactory进行初始化,这个步骤非常重要,对于注解配置,会扫描注入所有符合条件的BeanDefinition,方便后续实例化单例bean。传递入参有:

	public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) 

		// Invoke BeanDefinitionRegistryPostProcessors first, if any.
		Set<String> processedBeans = new HashSet<>();

		if (beanFactory instanceof BeanDefinitionRegistry) 
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) 
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) 
					BeanDefinitionRegistryPostProcessor registryProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
					registryProcessor.postProcessBeanDefinitionRegistry(registry);
					registryProcessors.add(registryProcessor);
				
				else 
					regularPostProcessors.add(postProcessor);
				
			

			// Do not initialize FactoryBeans here: We need to leave all regular beans
			// uninitialized to let the bean factory post-processors apply to them!
			// Separate between BeanDefinitionRegistryPostProcessors that implement
			// PriorityOrdered, Ordered, and the rest.
			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

			// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) 
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) 
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				
			
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
			currentRegistryProcessors.clear();

			// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) 
				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) 
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				
			
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
			currentRegistryProcessors.clear();

			// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
			boolean reiterate = true;
			while (reiterate) 
				reiterate = false;
				postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
				for (String ppName : postProcessorNames) 
					if (!processedBeans.contains(ppName)) 
						currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
						processedBeans.add(ppName);
						reiterate = true;
					
				
				sortPostProcessors(currentRegistryProcessors, beanFactory);
				registryProcessors.addAll(currentRegistryProcessors);
				invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
				currentRegistryProcessors.clear();
			

			// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
		

		else 
			// Invoke factory processors registered with the context instance.
			invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
		

		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let the bean factory post-processors apply to them!
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

		// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
		List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		for (String ppName : postProcessorNames) 
			if (processedBeans.contains(ppName)) 
				// skip - already processed in first phase above
			
			else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) 
				priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
			
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) 
				orderedPostProcessorNames.add(ppName);
			
			else 
				nonOrderedPostProcessorNames.add(ppName);
			
		

		// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

		// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
		List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
		for (String postProcessorName : orderedPostProcessorNames) 
			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		
		sortPostProcessors(orderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

		// Finally, invoke all other BeanFactoryPostProcessors.
		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
		for (String postProcessorName : nonOrderedPostProcessorNames) 
			nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		
		invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

		// Clear cached merged bean definitions since the post-processors might have
		// modified the original metadata, e.g. replacing placeholders in values...
		beanFactory.clearMetadataCache();
	

    处理步骤:
BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子类。调用顺序如下,从这里也可以看出,一个Spring容器的BFPP/BPP,是不会共享给其他Spring容器,需要手动注册。

  • 先对于BeanDefintionRegistryPostProcessor#postProcessBeanDefinitionRegistry()。

    • 先调用手动添加到ApplicationContext中的BeanDefinitionRegistryPostProcessor
    • 然后是容器中定义的BeanDefinitionRegistryPostProcessor,按照PriorityOrdered、Ordered、NonOrdered排序执行,相同情况下按照order值从小到大执行。
  • 再BeanFactoryPostProcessor#postProcessBeanFactory()。

    • 先调用手动添加到ApplicationContext中的BeanDefinitionRegistryPostProcessor#postProcessBeanFactory
    • 然后是容器中定义的BeanDefinitionRegistryPostProcessor#postProcessBeanFactory,
    • 对于手动添加的且只属于BeanFactoryPostProcessor,调用postProcessBeanFactory。
    • 找到容器中定义的BeanFactoryPostProcessor,按照PriorityOrdered、Ordered、NonOrdered排序执行,相同情况下按照order值从小到大执行

    CachingMetadataReaderFactoryPostProcessor主要是设置ConfigurationClassPostProcessor的setMetadataReaderFactory为SharedMetadataReaderFactoryBean,主要是对每个class resource,设置了缓存,见ConcurrentReferenceCachingMetadataReaderFactory

// org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer.CachingMetadataReaderFactoryPostProcessor#postProcessBeanDefinitionRegistry
		@Override
		public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException 
			register(registry);
			configureConfigurationClassPostProcessor(registry);
		

    org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer.ConfigurationWarningsPostProcessor,主要是对扫描org/org.springframework包进行警告。
    ConfigurationClassPostProcessor处理所有配置类,注册为beanDefinition的过程,详细见:spring boot配置类注册深入解析

4.5 registerBeanPostProcessors

    主要是从当前BeanFactory(不包含父BeanFactory)加载所有BeanPostProcessor,初始化,并设置到BeanFactory中。按照PriorityOrdered、Ordered、NonOrdered排序添加,相同情况下按照order值从小到大执行。BeanPostProcessor在bean的创建过程中生效。有4点需要注意:

  • 先注册的BPP会应用到后注册的BPP中,但是手动添加的会一直生效。
  • 由于BeanFactoryPostProcessor是在注册BeanPostProcessor之前实例化的,所以,BeanFactoryPostProcessor在被构建时,只有手动添加的会生效,其余的一律不生效。所以在BeanFactoryPostProcessor中使用@Value/@Resource等注解,不生效。
  • 对于BeanFactoryPostProcessor和BeanPostProcessor由于会提前初始化,所以尽量不要在这些类里边使用其他依赖,例如@Resource,可能会造成依赖过早初始化,而缺乏相关@BeanPostProcessor的处理,例如无法生成代理,事务不生效等。
  • 对于BeanFactoryPostProcessor和BeanPostProcessor由于会提前初始化,使用@Bean注册这类bean时,尽量声明为static,避免过早初始化宿主类,从而避免宿主类无法生成代理,事务不生效等问题。

    初始化时,有下面四个BeanPostProcessor

4.6 初始化事件多播器

    再这之前是初始化消息来源,支持国际化。初始化事件多播器默认底层使用的是SimpleApplicationEventMulticaster来实现。所有的ApplicationListener都会注册到这里

	protected void initApplicationEventMulticaster() 
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) 
			this.applicationEventMulticaster =
					beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
			if (logger.isTraceEnabled()) 
				logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
			
		
		else 
			this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
			beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
			if (logger.isTraceEnabled()) 
				logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
						"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
			
		
	

4.7 onRefresh

    这一步有两个作用:

  • 初始化ThemeSource
  • 对于springboot,则会创建tomcat,注册所有的servlet/filter等到tomcat servlet context。

    关于tomcat的构建,详细见:spring boot启动加载tomcat原理深度剖析

//org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh
	@Override
	protected void onRefresh() 
		super.onRefresh();
		try 
			createWebServer();
		
		catch (Throwable ex) 
			throw new ApplicationContextException("Unable to start web server", ex);
		
	
	private void createWebServer() 
		WebServer webServer = this.webServer;
		ServletContext servletContext = getServletContext();
		if (webServer == null && servletContext == null) 
			StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
			ServletWebServerFactory factory = getWebServerFactory();
			createWebServer.tag("factory", factory.getClass().toString());
			this.webServer = factory.getWebServer(getSelfInitializer());
			createWebServer.end();
			getBeanFactory().registerSingleton("webServerGracefulShutdown",
					new WebServerGracefulShutdownLifecycle(this.webServer));
			getBeanFactory().registerSingleton("webServerStartStop",
					new WebServerStartStopLifecycle(this, this.webServer));
		
		else if (servletContext != null) 
			try 
				getSelfInitializer().onStartup(servletContext);
			
			catch (ServletException ex) 
				throw new ApplicationContextException("Cannot initialize servlet context", ex);
			
		
		initPropertySources();
	

4.8 注册所有ApplicationListener到事件多播器

    主要是注册手动加入的ApplicationListener,然后从当前BeanFactory获取到ApplicationListener bean,添加到multicaster上,

// org.springframework.context.support.AbstractApplicationContext#registerListeners
	/**
	 * Add beans that implement ApplicationListener as listeners.
	 * Doesn't affect other listeners, which can be added without being beans.
	 */
	protected void registerListeners() 
		// Register statically specified listeners first.
		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);
		

		// Publish early application events now that we finally have a multicaster...
		Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
		this.earlyApplicationEvents = null;
		if (!CollectionUtils.isEmpty(earlyEventsToProcess)) 
			for (ApplicationEvent earlyEvent : earlyEventsToProcess) 
				getApplicationEventMulticaster().multicastEvent(earlyEvent);
			
		
	

    早期手动添加的ApplicationListener

    当前BeanFactory拥有的ApplicationListener bean:

4.9 非懒单例提前加载

    主要是两个作用:

  1. 获取所有的非懒单例bean,getBean构建
  2. 当所有单例bean加载完毕后,对于实现SmartInitializingSingleton接口的单例bean,调用其afterSingletonsInstantiated方法。
// org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization
	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) 
		// Initialize conversion service for this context.
		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));
		

		// Register a default embedded value resolver if no BeanFactoryPostProcessor
		// (such as a PropertySourcesPlaceholderConfigurer bean) registered any before:
		// at this point, primarily for resolution in annotation attribute values.
		if (!beanFactory.hasEmbeddedValueResolver()) 
			beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
		

		// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
		for (String weaverAwareName : weaverAwareNames) 
			getBean(weaverAwareName);
		

		// Stop using the temporary ClassLoader for type matching.
		beanFactory.setTempClassLoader(null);

		// Allow for caching all bean definition metadata, not expecting further changes.
		beanFactory.freezeConfiguration();

		// Instantiate all remaining (non-lazy-init) singletons.
		beanFactory.preInstantiateSingletons();
	

// org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
	@Override
	public void preInstantiateSingletons() throws BeansException 
		if (logger.isTraceEnabled()) 
			logger.trace("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<>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		for (String beanName : beanNames) 
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) 
				if (isFactoryBean(beanName)) 
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if (bean instanceof FactoryBean) 
						FactoryBean<?> factory = (FactoryBean<?>) bean;
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) 
							isEagerInit = AccessController.doPrivileged(
									(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						
						else 
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						
						if (isEagerInit) 
							getBean(beanName);
						
					
				
				else 
					getBean(beanName);
				
			
		

		// Trigger post-initialization callback for all applicable beans...
		for (String beanName : beanNames) 
			Object singletonInstance = getSingleton(beanName);
			if (singletonInstance instanceof SmartInitializingSingleton) 
				StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
						.tag("beanName", beanName);
				SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				if (System.getSecurityManager() != null) 
					AccessController.doPrivileged((PrivilegedAction<Object>) () -> 
						smartSingleton.afterSingletonsInstantiated();
						return null;
					, getAccessControlContext());
				
				else 
					smartSingleton.afterSingletonsInstantiated();
				
				smartInitialize.end();
			
		
	

    实现SmartInitializingSingleton接口的,主要有EventListenerMethodProcessor、AnnotationMBeanExporter、org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration.SameManagementContextConfiguration

todo 补充这里的使用情况。

4.10 完成刷新

  1. 初始化生命周期处理器,一般默认是DefaultLifecycleProcessor
  2. 调用所有的生命周期bean,实现Lifecycle接口,调用其start()。依据spring容器启动后和关闭前,需要实现SmartLifecycle,该类中isAutoStartup()返回true,表示自动在app.finishRefresh()/app.onDestroy()触发调用
  3. 发送ContextRefreshedEvent事件,表示容器启动成功。注意,如果当前容器有parent容器,则也会向parent容器发送该事件。
  4. 非原生镜像时,注册当前ApplicationContext作为MBean,只能注册一次。

springapplicationcontext.xml和hibernate.cfg.xml设置

applicationContext.xml配置<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http:/ 查看详情

springapplicationcontext.xml和hibernate.cfg.xml设置

applicationContext.xml配置<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="htt 查看详情

springapplicationcontext启动过程(代码片段)

...pringBoot的启动过程,在第5模块和第6模块,讲到了SpringApplicationContext的启动过程,会创建一个AnnotationConfigServletWebServerApplicationContext,之后调用相关的ApplicationContextInitializer对其进行初始化,包括设置parentcontext... 查看详情

从一个简单的例子看springapplicationcontext上下文隔离(代码片段)

前言   某天,浏览博客园的时候,对首页上面的一篇文章,标题为:<<一个普通类就能干趴你的springboot,你信吗?>>,文章链接:https://www.cnblogs.com/rongdi/p/11780204.html#4414216 很是感兴趣。点进去之后,大致看一... 查看详情

关于spring applicationContext

】关于springapplicationContext【英文标题】:aboutspringapplicationContext【发布时间】:2021-01-1714:10:26【问题描述】:我了解到当springapplicationContext被创建时,context本身将被注册为bean。所以我做了一个简单的代码,并期望applicationContext... 查看详情

开机自启监听

一、创建一个类使其继承BroadcastReceiver并且复写onReceive方法publicclassBootReceiverextendsBroadcastReceiver{@OverridepublicvoidonReceive(Contextcontext,Intentintent){//开启mainActivityIntentautoRestart=newIntent(context 查看详情

virtualbox虚机无法启动因断电

 Thevirtualmachine‘nn1‘hasterminatedunexpectedlyduringstartupwithexitcode1(0x1).Moredetailsmaybeavailablein‘C:UsersstudentVirtualBoxVMsHadoop n1LogsVBoxHardening.log‘. 笔记本电池耗尽,断电关机,重启 查看详情

仅在 Spring Application Context 启动时运行方法?

】仅在SpringApplicationContext启动时运行方法?【英文标题】:RunamethodonlyatSpringApplicationContextstartup?【发布时间】:2014-06-1302:08:24【问题描述】:我需要在我的Web应用程序的SpringApplicationContext启动后运行一个方法。我查看了thisquestion... 查看详情

dolphinscheduler服务启停(代码片段)

1、服务启停cd /home/hadoop/app/dolphinscheduler/bin⼀键停⽌集群所有服务sh ./bin/stop-all.sh⼀键开启集群所有服务sh ./bin/start-all.sh启停Mastersh ./bin/dolphinscheduler-daemon.sh start master-serversh ./bin/dolphinscheduler-daem 查看详情

kafka群启脚本

#!/bin/bashcase$1in"start")foriinhadoop120hadoop121hadoop122doecho"************$i*************"ssh$i"/.../kafka/bin/kafka-server-start.sh-daemon/.../kafka/config/server.prope 查看详情

openwrt不能自启插件原因

...AAndroidTV版(乐视超3X55)root,将自己的软件设置为开机自启、系统软件,卸载系统应用等问题总结Ubuntu设置程序开机自启或者开机禁止加载Linux下设置Nginx开机自启centos7设置tomcat开机自启Jobforredis-server.servicefailedbecausethecontrolproces... 查看详情

Spring ApplicationContext - 资源泄漏:“上下文”永远不会关闭

】SpringApplicationContext-资源泄漏:“上下文”永远不会关闭【英文标题】:SpringApplicationContext-Resourceleak:\'context\'isneverclosed【发布时间】:2012-12-2011:31:49【问题描述】:在SpringMVC应用程序中,我使用以下方法在其中一个服务类中初... 查看详情

广州启帆机器人搬码拣画册

广州启帆机器人搬码拣画册  ?????????????????for??global??enterprises          查看详情

android开机自启服务

1packagecom.example.lenovo.guangbo;23importandroid.app.Service;4importandroid.content.Intent;5importandroid.os.IBinder;6importandroid.util.Log;78publicclassMyServiceextendsService{9publicMyService(){1 查看详情

启心动念——冲刺集合

...目标针对不足的地方进行思考和总结小组的组号和队名1启心动念小组的队长姓名吴怡君随笔集合日志名称具体工作(当天完成的工作量)剩余的工作量已完成工作量占总工作量的百分比冲刺随笔1查阅资料,完成组内分工(10%)9... 查看详情

hivemetastorehiveserver2服务启停脚本(代码片段)

hivemetastore、hiveserver2服务启停脚本cat~/bin/mshs2.sh#!/bin/bashcase$1in"start")echo"----"echo"--1.startmetastore...--"nohuphive--servicemetastore-p9083>>/usr/hdp/hive/logs/me 查看详情

记录一次docker服务启不起来的案子

...统上把libapparmor.so.1文件copy到故障机,然后在做软连接。启服务docker。奇迹发生。docker服务启起来了!  查看详情

lightdb22.2-新增集群启停脚本(代码片段)

lightdb22.2-新增集群启停脚本lightdb22.2版本新增了集群启停脚本,脚本名为lightdb_service.py。使用python2.7开发。使用该脚本会对涉及的lightdb,ltcluster,keepalive进行相应操作。由于需要依赖installer安装后生成的json文件来获取集群信息&... 查看详情