In depth analysis of Spring source code -- Annotation config application context

Today's pig's foot is annotationconfiguapplicationcontext. It's a long time ago to start looking at this class. It looks like a few simple codes, but there are tens of thousands of them behind it. First, the overall analysis, and then the local analysis. It's called ACAC

What is ACAC for

This class is the application context we often refer to, so to speak (personal understanding). It contains all the information of Spring application (including configuration information), and it is responsible for integrating the scattered information and functions in Spring.
When it comes to ApplicationContext, there are three ways to load the application context

  • AnnotationConfigApplicationContext
  • ClassPathXmlApplicationContext
  • FileSystemXmlApplicationContext

How does ACAC perform initialization

It has four construction methods

  • AnnotationConfigApplicationContext()
  • AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory)
  • AnnotationConfigApplicationContext(Class<?>... componentClasses)
  • AnnotationConfigApplicationContext(String... basePackages)
  1. No parameter Construction: initializes the reader and scanner. Before instantiation, the construction method of the parent class will be called to assign a value of DefaultListableBeanFactory to BeanFactory
	public AnnotationConfigApplicationContext() {
		/**
		 * Instantiate reader
		 * AnnotatedBeanDefinition  Annotated Bean
		 * Read the annotated beans
		 */
		this.reader = new AnnotatedBeanDefinitionReader(this);

		/**
		 * Instantiate a scanner
		 * Ability to scan classes, packages, and convert to bd
		 * The purpose of this scan is to scan manually. The @ ComponentScan you usually use doesn't use this scanner, but a new ClassPathBeanDefinitionScanner
		 */
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}


    // Nonparametric construction of the parent class GenericApplicationContext
	public GenericApplicationContext() {
		this.beanFactory = new DefaultListableBeanFactory();
	}
  1. Select the incoming BeanFactory by yourself
	public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {
		// Parent class method
		super(beanFactory);
		this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}
  1. With one or more configuration classes
	public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
		//The parameterless construction method called in this indirectly calls the parameterless construction of the parent class to initialize BeanFactory
		//Initializing a reader and a scanner in your own constructor
		this();
		//Read one / more classes and register to map
		register(componentClasses);
		refresh();
	}
  1. With package scan
	public AnnotationConfigApplicationContext(String... basePackages) {
		this();
		scan(basePackages);
		refresh();
	}

It can be seen from this that refresh is required for every add operation of ApplicationContext (whether it is a configuration file or a common class). The following code will report the following exception if register operation is performed after the context initialization session is completed and refresh operation is not performed

AnnotationConfigApplicationContext applicationContext=
				new AnnotationConfigApplicationContext();
		applicationContext.register(AppConfig.class);
		System.out.println(applicationContext.getBean(AppConfig.class));

// Un refresh exception occurred
> Task :My-Spring:AnnotationTest.main() FAILED
Exception in thread "main" java.lang.IllegalStateException: org.springframework.context.annotation.AnnotationConfigApplicationContext@4edde6e5 has not been refreshed yet

It can be seen from this that the execution process of refresh() is the context life cycle

Life cycle of ACAC

In view of the above tests, I will treat each non empty method in refresh as a life process

	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			//The preparatory work includes setting the start time, activating the container, and obtaining the current environment verification mark that can be resolved
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory
			//Get DefaultListableBeanFactory
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			//Prepare BeanFactory and put in some necessary components of BeanFactory
			prepareBeanFactory(beanFactory);

			try {

				// Allows post-processing of the bean factory in context subclasses.
				//There is no code in it. It needs to be expanded
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				//Execute the registered factory processors in the Spring environment
				//Call the processorsbeanfactory defined by the user-defined (need to add it into the annotationconfigpplicationcontext) and the BeanFactoryPostProcessor defined by spring
				invokeBeanFactoryPostProcessors(beanFactory);

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

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

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

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

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

				// Instantiate all remaining (non-lazy-init) singletons.
				// It is very important to initialize the remaining singleton objects
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				// Publish context refresh 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();
			}
		}
	}	

I spent a diagram to analyze the process, as follows:

This is the life cycle of annotation config application context. In the next article, we will analyze these life processes!

115 original articles published, 76 praised, 10000 visitors+
Private letter follow

Tags: Spring Session Java

Posted on Sun, 15 Mar 2020 21:01:18 -0700 by La Parka