Spring is a familiar framework for any Java developer, but if you really want to understand its implementation and how it works, you need to analyze and think about the Spring source code.

Download the source code

Source download view visible: view spring source

Understand the Spring container to refresh the logical, namely to explore AbstractApplicationContext# refresh () method were done. This method is the core of Spring Bean loading and defines the entire Spring context loading process.

In this article, we’ll examine the refresh logic of the entire Spring container in terms of the various methods in Refresh.

The refresh method

  • PreareRefresh Preparation for work before refresh
  • ObtainFreshBeanFactory gets the refreshed internal beanFactory instance of the subclass
  • PrepareBeanFactory registers the necessary system-level beans for the container
  • PostProcessBeanFactory allows container subclasses to de-register postProcessor
  • InvokeBeanFactoryPostProcessors call container container level registered post processor
  • RegisterBeanPostProcessors registered Bean with the container level post processor
  • InitMessageSource Initializes internationalization configuration
  • InitApplicationEventMulticaster initialization event publishers components
  • OnRefresh is reserved for subclasses to initialize other special beans before the singleton Bean is initialized
  • RegisterListeners Register event listeners with the previous event publisher component
  • FinishBeanFactoryInitialization set the system level of service, instantiate all the lazy loading singleton
  • FinishRefresh triggers the callback method when the initialization is complete and publishes the event when the container refresh is complete to the listener
  • ResetCommonCaches resets the common cache in the Spring kernel

Ok, let’s examine the refresh method

@Override
public void refresh(a) throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
            // Prepare this context for the refresh. Update of status values
            prepareRefresh();
		
            // Tell the subclass to refresh the internal bean factory. This section analyzes only the creation of a beanFactory
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
		
            // Register some system beans required by the container, such as classLoader, etc
            prepareBeanFactory(beanFactory);
        
            try {
		// Allow subclasses of the container to register postProcessor, hook methods
		postProcessBeanFactory(beanFactory);
			
                / / activate the registration for bean BeanFactoryPostProcessors in the container
		// Scan all beanDefinitions in the application and register them in the container
		invokeBeanFactoryPostProcessors(beanFactory);
			
                // Register the BeanPostProcessor that intercepts bean creation
		registerBeanPostProcessors(beanFactory);
			
                // Provide a message source for ApplicationContext
		initMessageSource();
			
                / / initialize ApplicationEventMulticaster such as event publishers,
		// We can store all event listeners and notify different event listeners based on different events.
		initApplicationEventMulticaster();
			
                / / reserved for AbstractApplicationContext subclass is used to initialize other special bean,
		// This method needs to be called before all singleton beans are initialized
		// For example, the Web container initializes ThemeSource related beans.
		onRefresh();
			
                // Register listeners (check listener beans and register them)
		registerListeners();
			
                // Set a custom type converter ConversionService,
		// Set custom AOP-related class LoadTimeWeaverAware,
		// Clear the temporary ClassLoader
		// Instantiate all classes (except lazily loaded classes)
		finishBeanFactoryInitialization(beanFactory);
			
                / / initializes the container to the life cycle of the event handler, (the default use DefaultLifecycleProcessor), call extends SmartLifecycle the start method of the interface
		// After the Spring container has loaded all the beans and initialized them, it then calls back the corresponding method (the start method) in the class that implements the interface.
		ContextRefreshedEvent to the event listener after refreshing the event with the release container
		finishRefresh();
			} 
        // ··· catch }}Copy the code

The refresh method

PreareRefresh Work preparation before refresh

Container preparation: Record the start time startupDate of the Spring container, mark the container as active, initialize the context such as file path information, and verify whether required properties are filled.

protected void prepareRefresh(a) {
	// Switch to active.
	this.startupDate = System.currentTimeMillis();
	this.closed.set(false);
	// 1. Set the status of the container to active
	this.active.set(true);
	/ /... logger
	
        // 2. Initialize the Environment propertySources property
	
      
	initPropertySources();
	
        // 3. Verify that all Environment requiredProperties exist
	/ / please refer ConfigurablePropertyResolver# setRequiredProperties
	getEnvironment().validateRequiredProperties();
    
	// Store pre-refresh ApplicationListeners...
    
	// 4. Create an event set
	this.earlyApplicationEvents = new LinkedHashSet<>();
}
Copy the code

ObtainFreshBeanFactory obtains the internal beanFactory instance after subclass refresh

Get into the bean tag in the XML configuration of various attributes, encapsulated into a BeanDefinition object, then the object to our beanDefinitionMap, beanDefinitionNames IOC container, For use in the IOC container and create conditions to obtain the ConfigurableListableBeanFactory is created.

This method is carefully analyzed in “Spring source analysis (2) BeanFactory creation and XML configuration parsing”.

PrepareBeanFactory registers the necessary system-level beans for the container

As you can see, after the beanFactory is created, the code continues to register some system beans needed in the container, such as classLoader, and so on.

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	// Set beanFactory to use the container's classloader
	beanFactory.setBeanClassLoader(getClassLoader());
	// Set beanFactory's expression language handler
        // Spring3 began to add support for language expressions. The default is to use the form #{bean.xxx} to call the related property values
	beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
	// Add a default propertyEditor for beanFactory
	beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
	// Add the function of this handler: inject ApplicationContext objects when application-defined beans implement the ApplicationContextAware interface
	beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
	// If a bean depends on the implementation classes of the following interfaces, ignore them when autowiring.
	// Spring handles these dependencies in other ways.
	beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
	beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
	beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
	beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

	// Fix the dependencies, where you register some special rules for autoluing, such as the implementation class of the BeanFactory interface, and specify the current BeanFactory at runtime
	beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
	beanFactory.registerResolvableDependency(ResourceLoader.class, this);
	beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
	beanFactory.registerResolvableDependency(ApplicationContext.class, this);

	// Register an early post-processor that detects internal beans as application listeners
	/ / ApplicationListenerDetector role is to determine whether a particular Bean ApplicationListener,
	// If so, join the event listener queue.
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

	// If you find a LoadTimeWeaver, you are ready to add the back-end processor to the beanFactory
	if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
		// Set temporary class loaders for type matching.
		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
	}

	// Register the default environment
	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

PostProcessBeanFactory allows container subclasses to deregister postProcessor

Spring then allows container subclasses to de-register postProcessor, which Spring reserves for subclasses to implement.

Five, the invokeBeanFactoryPostProcessors call container container level registered post processor

In invokeBeanFactoryPostProcessors method, we gave PostProcessorRegistrationDelegate concrete implementation logic agent to handle, This is basically a class that aggregates the call logic of the registered PostProcessor into one class. Let’s follow this up:

public static void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory, List
       
         beanFactoryPostProcessors)
        {

	/ / if there is one BeanDefinitionRegistryPostProcessor priority
	Set<String> processedBeans = new HashSet<>();
	// If BeanDefinitionRegistry type is present
	if (beanFactory instanceof BeanDefinitionRegistry) {
		BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
		// To record the regular BeanFactoryPostProcessor
		List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
		/ / BeanDefinitionRegistryPostProcessor is recorded
		List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
		// Iterates through all the BeanFactoryPostProcessors passed in (they are not registered in the container as beans)
		// Divide the BeanFactoryPostProcessor passed in with all parameters into two groups:
		/ / BeanDefinitionRegistryPostProcessor and conventional spring BeanFactoryPostProcessor
		/ / 1. If is BeanDefinitionRegistryPostProcessor now perform postProcessBeanDefinitionRegistry (),
		// 2. Otherwise, the record will be a normal BeanFactoryPostProcessor and no processing will be performed
		for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
			if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
				BeanDefinitionRegistryPostProcessor registryProcessor =
						(BeanDefinitionRegistryPostProcessor) postProcessor;
				registryProcessor.postProcessBeanDefinitionRegistry(registry);
				registryProcessors.add(registryProcessor);
			}
			else{ regularPostProcessors.add(postProcessor); }}/ / used to record the current BeanDefinitionRegistryPostProcessor was about to be executed
		List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
		/ / first of all, to implement the interface priority order form of Bean BeanDefinitionRegistryPostProcessor make calls
		/ / register find all containers for BeanDefinitionRegistryPostProcessor postProcessor name array
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true.false);
		for (String ppName : postProcessorNames) {
			/ / traversal container, rear BeanDefinitionRegistryPostProcessor type of processor Bean instance to add to the current register in the processor
			if(beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); }}// Order by priority
		sortPostProcessors(currentRegistryProcessors, beanFactory);
		registryProcessors.addAll(currentRegistryProcessors);
		/ / execute sequentially BeanDefinitionRegistryPostProcessors
		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
		currentRegistryProcessors.clear();
		// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
		/ / the second interface to realize the Ordered BeanDefinitionRegistryPostProcessors invoked
		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);
			}
		}
		// Order by Order
		sortPostProcessors(currentRegistryProcessors, beanFactory);
		// Make the fully ordered BeanDefinitionRegistry
		registryProcessors.addAll(currentRegistryProcessors);
		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
		currentRegistryProcessors.clear();
		// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
		/ / in the end, the remaining BeanDefinitionRegistryPostProcessors execution
		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);
			currentRegistryProcessors.clear();
		}
		/ / because BeanDefinitionRegistryPostProcessor inherited from spring BeanFactoryPostProcessor, so here
		/ / for all BeanDefinitionRegistryPostProcessor also call its methods postProcessBeanFactory ()
		invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
		// Call the method postProcessBeanFactory() on all regular BeanFactoryPostProcessors
		invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
	}
	else {
		// If both are regular BeanFactoryPostProcessor, call its method postProcessBeanFactory()
		invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
	}
	/ / the above logic performed in the form of parameters of the incoming BeanDefinitionRegistryPostProcessor and common spring BeanFactoryPostProcessor
	/ / BeanDefinitionRegistryPostProcessor also carried out inside the container, so the container left spring BeanFactoryPostProcessor need to deal with
	// The logic is the same, which can be PriorityOrdered, Ordered, or neither
	/ /...
}
Copy the code

Learn more about full link resolution in the annotated article series

Six, registerBeanPostProcessors registered Bean with the container level post processor

To allow container subclasses to deregister postProcessor, the hook method facilitates processing of the postProcessor when the getBean method is called to create bean instances

InitMessageSource Initializes internationalization configuration

Some internationalization-related configurations, if not defined in this context, use the parent context’s internationalized resources.

protected void initMessageSource(a) {
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
		this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
		// The parent context's MessageSource is known using this context's MessageSource.
		if (this.parent ! =null && this.messageSource instanceof HierarchicalMessageSource) {
			HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
			if (hms.getParentMessageSource() == null) {
				// If no parent MessageSource has been registered, only the parent context is set to the parent MessageSource
				// registered already.hms.setParentMessageSource(getInternalParentMessageSource()); }}if (logger.isTraceEnabled()) {
			logger.trace("Using MessageSource [" + this.messageSource + "]"); }}else {
		// Use an empty MessageSource to accept calls to the getMessage method
		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

Eight, initApplicationEventMulticaster initialization event publishers components

Initialize ApplicationEventMulticaster such as event publishers can store all event listeners information, and according to the different events, notice different event listeners

protected void initApplicationEventMulticaster(a) {
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	/ / if the container is ApplicationEventMulticaster bean instance,
        / / applicationEventMulticaster is assigned to the containers
	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 {
		/ / not create a new SimpleApplicationEventMulticaster,
		/ / and completed the SimpleApplicationEventMulticaster Bean registration
		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

OnRefresh is reserved for subclasses to initialize other special beans before the singleton Bean is initialized

Template method, which can be overridden to add context-specific refresh work. For example: StaticWebApplicationContext# onRefresh () to initialize the theme USES The method in a particular instance instantiation (finishBeanFactoryInitialization) before call special bean initialization.

RegisterListeners Register event listeners with the previous event publisher component

Add the application listener as the listener bean. If it doesn’t affect other listeners, you can add them without beans.

protected void registerListeners(a) {
	// First register the static listener specified
	for(ApplicationListener<? > listener : getApplicationListeners()) { getApplicationEventMulticaster().addApplicationListener(listener); }// Don't initialize FactoryBean here. We need to keep all the normal beans (event listeners) uninitialized.
	// Let the post processor apply to them!
	String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true.false);
	for (String listenerBeanName : listenerBeanNames) {
		getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
	}
    
	/ / at this point, has completed the listeners registered to ApplicationEventMulticaster,
	// Now we finally have a multiplexer to publish previous application events to listeners.
	Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
	this.earlyApplicationEvents = null;
	if(earlyEventsToProcess ! =null) {
		for(ApplicationEvent earlyEvent : earlyEventsToProcess) { getApplicationEventMulticaster().multicastEvent(earlyEvent); }}}Copy the code

11, finishBeanFactoryInitialization setting system level service, instantiate all the lazy loading singleton

Complete the initialization of the beanFactory for this context, initializing all remaining singleton beans.

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
	// Initialize the converter for this container
	// It is the responsibility of the converter to handle the type conversion when assigning values to bean instance member variables by configuration
	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));
	}

	// If the bean postProcessor is not registered, the default parser is registered
	/ / (for example, is mainly used to parse the properties file is accomplished)
	// @value annotation or use ${} in XML to configure the environment
	if(! beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); }// AOP is divided into three types: compile-time weaving, classload-time weaving, and run-time weaving
	// LoadTimeWeaving is the second type, which is used for weaving through the JVM
	// Initialize LoadTimeWeaverAware beans to register their transformers as early as possible
	String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false.false);
	for (String weaverAwareName : weaverAwareNames) {
		getBean(weaverAwareName);
	}

	// Stop using temporary class loaders for type matching.
	beanFactory.setTempClassLoader(null);

	// Freeze the configuration to allow caching of all bean definition metadata with no further changes expected
	beanFactory.freezeConfiguration();

	// Instantiate all remaining singletons (non-lazy-init)
	beanFactory.preInstantiateSingletons();
}
Copy the code

FinishRefresh triggers the callback method when the initialization is complete and publishes the event that the container refresh is complete to the listener

After the Spring container loads all the beans and completes the initialization, it then calls back to the corresponding method (the start() method) in the class that implements the interface and publishes the container flush finished event ContextRefreshedEvent to the corresponding event listener

protected void finishRefresh(a) {	
    // Clear the context-level cache of resources (such as scanned ASM metadata)
    clearResourceCaches();    	
    // Initialize the lifecycle handler for this context
    initLifecycleProcessor();    	
    // First propagate the refresh to the lifecycle processor
    getLifecycleProcessor().onRefresh();    	
    // Publish the final event
    publishEvent(new ContextRefreshedEvent(this));    	
    // If it is active, it participates in the LiveBeansView MBean.
    LiveBeansView.registerApplicationContext(this);
}
Copy the code

ResetCommonCaches resets the common cache in the Spring kernel

Reset Spring common reflection metadata caching, especially ReflectionUtils AnnotationUtils, ResolvableType and CachedIntrospectionResults cache.

protected void resetCommonCaches(a) {	
    ReflectionUtils.clearCache();	
    AnnotationUtils.clearCache();	
    ResolvableType.clearCache();	
    CachedIntrospectionResults.clearClassLoader(getClassLoader());
}
Copy the code

conclusion

In summary, the Spring container to refresh the logic mainly in AbstractApplicationContext# refresh () method, this method is brief to empty the beanFactory as the initial state, and then according to the intention of the application to fill all kinds of bean instance.

This article is based on the spring framework 5.2.10.RELEASE version for analysis