Series of articles

Spring is no stranger to programmers, and it is very useful for us to master it. Many of the frameworks behind it are based on Spring extensions, and after you understand the source code, it is good for your ability to deal with secondary development, so it is important to master it. Let’s get right to the point. The Spring startup process is actually the Ioc container initialization and loading of beans; This article is mainly to learn to record the Ioc container initialization, novice road, if there is an error, please correct!


The article directories


preface

This article is debugSpring source code, step by step record learning to understand Spring


You’re familiar with this, which is to create a Spring object, read a configuration file, and then we’re going to break it

 		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Copy the code

Let’s go in step by step

ClassPathXmlApplicationContext create

ClassPathXmlApplicationContext mainly did three things

1. Invoke the parent constructor to create objects

2. Load the configuration file path

3. Perform the refresh() method, the most important and true entry to the source code





The refresh() method: initialize the IOC container

Refresh; refresh;

	public void refresh(a) throws BeansException, IllegalStateException {
  		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			// Do some basic preparatory work to set the corresponding flag, close state, start time etc. Initialize the related object configuration etc
			/** * 1. Set the container startup time * 2. Set the active state to true * 3. Set the shutdown state to false * 4. Get the Environment object and load the current system property value into the Environment object * 5. Prepare listeners and event collection objects, which default to empty collection */
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.

			/ / create the Bean container factory (create a container object: DefaultListableBeanFactory, reads the XML file information, generate BeanDefinition object)
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			// Set the property value for the current bean container factory (the BeanDefinition object populates the related property)
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				// Empty method, not implemented, for future extension
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				// Executes the beanDefinition enhancer (called before the singleton instance is initialized, because it makes no sense to increment once it is instantiated)
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				// Instantiate and register beanPostProcessors
				registerBeanPostProcessors(beanFactory);

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

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

				// Initialize other special beans in specific context subclasses.
				// Is currently an empty method for subclass extension implementation
				onRefresh();

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

				// Instantiate all remaining (non-lazy-init) singletons.
				// Instantiate the remaining instance objects (not lazily loaded)
				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(); }}}Copy the code

1. PrepareRefresh () : Pre-processing before creating the IOC container

	protected void prepareRefresh(a) {
		// Switch to active.
		this.startupDate = System.currentTimeMillis();
		this.closed.set(false);
		this.active.set(true);

		if (logger.isDebugEnabled()) {
			if (logger.isTraceEnabled()) {
				logger.trace("Refreshing " + this);
			}
			else {
				logger.debug("Refreshing "+ getDisplayName()); }}// Initialize any placeholder property sources in the context environment.
		In Spring, it is an extension method for other subclasses, such as SpringMVC, which has an implementation for it
		initPropertySources();

		// Validate that all properties marked as required are resolvable:
		// see ConfigurablePropertyResolver#setRequiredProperties
		// 1. The current method of getEnvironment is the first focus of the Spring process
		// Get the environment object and validate the property resource
		getEnvironment().validateRequiredProperties();

		// Store pre-refresh ApplicationListeners...

		/ / storing this listener to refresh the application (convenient do extension implementation) is a collection of empty in the spring, but in the initialization of springBoot enclosing applicationListeners has a value
		if (this.earlyApplicationListeners == null) {
			this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
		}
		else {
			// Reset local application listeners to pre-refresh state.
			this.applicationListeners.clear();
			this.applicationListeners.addAll(this.earlyApplicationListeners);
		}

		// Allow for the collection of early ApplicationEvents,
		// to be published once the multicaster is available...
		// Create a collection of listener events
		this.earlyApplicationEvents = new LinkedHashSet<>();
	}
Copy the code

ObtainFreshBeanFactory () : Create the Bean container factory and parse the XML configuration file to generate the generated BeanDefinition object

	protected final void refreshBeanFactory(a) throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			// Create a bean factory
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			// To serialize the specified ID, you can deserialize the ID to the beanFactory object
			beanFactory.setSerializationId(getId());
			// Customize beanFactory to set properties, including whether objects with different definitions of the same name are allowed to be overridden and loop dependencies
			customizeBeanFactory(beanFactory);
			// Read the information in the XML configuration file to generate beanDefinitions
			loadBeanDefinitions(beanFactory);
			this.beanFactory = beanFactory;
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for "+ getDisplayName(), ex); }}Copy the code

Did you get the type of the beanFactory: DefaultListableBeanFactory, this is our bean plant

	public final ConfigurableListableBeanFactory getBeanFactory(a) {
		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;
	}
Copy the code

PrepareBeanFactory () : Sets the property value for the current bean container factory

	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));
		// Set the aware interface to be ignored. Aware related processing is not implemented here, so it will be added to a collection and will be processed later in the instantiation
		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());
		}
	}
Copy the code

4. InvokeBeanFactoryPostProcessors () : perform beanDefinition enhancer

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

		// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
		// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
		if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			beanFactory.setTempClassLoader(newContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); }}Copy the code

5. RegisterBeanPostProcessors () : beanPostProcessors instantiate and registration

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
	}
Copy the code

6. InitMessageSource () : Internationalization setting

	protected void initMessageSource(a) {
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
			this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
			// Make MessageSource aware of parent MessageSource.
			if (this.parent ! =null && this.messageSource instanceof HierarchicalMessageSource) {
				HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
				if (hms.getParentMessageSource() == null) {
					// Only set parent context as parent MessageSource if no parent MessageSource
					// registered already.hms.setParentMessageSource(getInternalParentMessageSource()); }}if (logger.isTraceEnabled()) {
				logger.trace("Using MessageSource [" + this.messageSource + "]"); }}else {
			// Use empty MessageSource to be able to accept getMessage calls.
			DelegatingMessageSource dms = new DelegatingMessageSource();
			dms.setParentMessageSource(getInternalParentMessageSource());
			this.messageSource = dms;
			beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
			if (logger.isTraceEnabled()) {
				logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]"); }}}Copy the code

7. InitApplicationEventMulticaster () : initialize radio apparatus

	protected void initApplicationEventMulticaster(a) {
		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() + "]"); }}}Copy the code

8 registerListeners are registered

	protected void registerListeners(a) {
		// 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); }}}Copy the code

9. FinishBeanFactoryInitialization () : the instantiation of the rest of the instance objects (not lazy loading)

	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 bean post-processor
		// (such as a PropertyPlaceholderConfigurer 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();
	}
Copy the code

10finishRefresh: Finishes the refresh and publishes some events

protected void finishRefresh(a) {
		// Clear context-level resource caches (such as ASM metadata from scanning).
		clearResourceCaches();

		// Initialize lifecycle processor for this context.
		initLifecycleProcessor();

		// Propagate refresh to lifecycle processor first.
		getLifecycleProcessor().onRefresh();

		// Publish the final event.
		publishEvent(new ContextRefreshedEvent(this));

		// Participate in LiveBeansView MBean, if active.
		LiveBeansView.registerApplicationContext(this);
	}
Copy the code

Write in the last

Welcome to pay attention to my wechat public number [Village of apes] to talk about Java interview plus my wechat for further communication and learning if it shows frequent, wechat mobile search [codeyuanzhicunup] can be added if there are related technical problems welcome to leave a message to discuss, the public number is mainly used for technology sharing, Including often meet test analysis, as well as source code interpretation, micro service framework, technology hot spots.

Source code road first step, refueling mutual encouragement QAQ