Spring initializes Ioc I

Spring IOC source code parsing based on annotations, version 5.1.x

Initializing bean s through the Spring context

Annotation class, annotationconfigpplicationcontext can be used to load Spring context based on java configuration class (various annotations), which is better than using application.xml More concise and convenient.

package com.jingjing.spring;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

/**
 * Which directory bean s need to be scanned
 * Created by yuanqingjing on 2020/3/7
 */
@ComponentScan("com.jingjing")
public class Test {

    public static void main(String[] args) {

       
        /**
         * Initialize bean init
         * 1.Scan the class
         * 2.Instantiate bean
         */
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Test.class);
        BeanTest beanTest= context.getBean(BeanTest.class);
        System.out.println(beanTest);


    }


}
package com.jingjing.spring;

import org.springframework.stereotype.Component;

/**
 * Created by yuanqingjing on 2020/3/7
 */
@Component
public class BeanTest{

    public BeanTest() {
        System.out.println("init");
    }

  
}

Annotationconfidapplicationcontext constructor

   


        /**
         * Register the bean s in the corresponding configuration class into the container
         * Create a new annotation configuration context, get bean definitions from the annotatedClasses configuration class, and then
         * bean definition Update to context
	 * Create a new AnnotationConfigApplicationContext, deriving bean definitions
	 * from the given annotated classes and automatically refreshing the context.
	 * @param annotatedClasses one or more annotated classes,
	 * e.g. {@link Configuration @Configuration} classes
	 */
	public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
		//Because it has a parent class, it will first call the parent class constructor, and then call its own constructor
		//Initializing a reader and a scanner in your own constructor
		//The parent class constructor creates a beanfactory defaultlistablebeanfactory
		this();
                //Turn annotation class into a BeanDefinition
		register(annotatedClasses);
                //Scan the Class, change the Class under these paths into a BeanDefinition, and then change some beandefinitions into bean objects
		refresh();
	}

this() method parsing

Annotationconfiguapplicationcontext inherits from GenericApplicationContext

        /**
         * The parent class GenericApplication default constructor creates a BeanFactory  
         * DefaultListableBeanFactory,A very important BeanFactory
	 * Create a new GenericApplicationContext.
	 * @see #registerBeanDefinition
	 * @see #refresh
	 */
	public GenericApplicationContext() {
		this.beanFactory = new DefaultListableBeanFactory();
	}
     /**
         * Default constructor 
         * Create an annotation based BeanDefinition reader
         * Create a BeanDefinition scanner that scans the path
	 * Create a new AnnotationConfigApplicationContext that needs to be populated
	 * through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
	 */
	public AnnotationConfigApplicationContext() {
		this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

Analysis of register (annotated classes) method

/**
*It's actually calling the register method of the AnnotatedBeanDefinitionReader class
*/
public void register(Class<?>... annotatedClasses) {
		Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
		this.reader.register(annotatedClasses);
	}

The core logic is the doRegisterBean() method of AnnotatedBeanDefinition

public void register(Class<?>... annotatedClasses) {
		Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
		this.reader.register(annotatedClasses);
	}


public void registerBean(Class<?> annotatedClass) {
		doRegisterBean(annotatedClass, null, null, null);
	}

    /**
	 * Register a bean from the given bean class, deriving its metadata from
	 * class-declared annotations.
	 * @param annotatedClass the class of the bean
	 * @param instanceSupplier a callback for creating an instance of the bean
	 * (may be {@code null})
	 * @param name an explicit name for the bean
	 * @param qualifiers specific qualifier annotations to consider, if any,
	 * in addition to qualifiers at the bean class level
	 * @param definitionCustomizers one or more callbacks for customizing the
	 * factory's {@link BeanDefinition}, e.g. setting a lazy-init or primary flag
	 * @since 5.0
	 */
	<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
			@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {

		//Change the configuration class to AnnotatedGenericBeanDefinition, which inherits BeanDefinition,
		//The function is to define the data structure of a bean. getmetadata() can get the annotation information on the bean
		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
		//@Conditional assembly condition judge whether to skip registration
		if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
			return;
		}

		//Set callback
		abd.setInstanceSupplier(instanceSupplier);
		//Resolve the bean Scope (singleton or prototype). If @ Scope annotation is available, the bean Scope will be resolved. Otherwise, singleton will be the default
		ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
		//Scope written back to beandefinition
		abd.setScope(scopeMetadata.getScopeName());
		//Generate bean configuration class beanName
		String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
		//The general annotation is parsed into the BeanDefinition structure, mainly dealing with the five annotations of lazy Primary DependsOn Role Description
		AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
		//@Qualifier special qualifier handling
		if (qualifiers != null) {
			for (Class<? extends Annotation> qualifier : qualifiers) {
				//If the Primary annotation is configured, set the current bean as the preferred bean when autowire is automatically assembled
				if (Primary.class == qualifier) {
					abd.setPrimary(true);
				}
				//Set lazy load to delay load
				else if (Lazy.class == qualifier) {
					abd.setLazyInit(true);
				}
				else {
					//Add additional annotations to the abd structure
					abd.addQualifier(new AutowireCandidateQualifier(qualifier));
				}
			}
		}
		//The user-defined bean registration is usually used after the applicationContext is created to manually register the bean in the way of - lambda expression in the container
		// applicationContext.registerBean(Test.class,()->new Test());
		for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
			//Custom bean added to BeanDefinition
			customizer.customize(abd);
		}

		//Encapsulate a bean definition holder according to bean name bean definition information
		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
		//Create proxy object
		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
		//Go deep into the code to find out whether the registerBeanDefinition() of DefaultListableBeanFactory is the last call
		//The logic is to put beanname and beandefinition into BeanDefinitionMap of BeanFactory
		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
	}

In fact, the register method mainly completes the parsing and registration of configuration classes, mainly including the following steps

1. The class annotatedClass will be configured, and the Bean definition will be used to resolve the definition information of the Bean, mainly some annotation information

2.bean Scope processing. If there is @ Scope scope, it will return to the Scope. If there is no Scope, it will be Singleton by default

3. Parsing common annotations with annotations configutils

4. Register bean name (bean definition) to the Ioc container

Analysis of refresh method

The refresh() method is implemented in the AbstractApplicationContext class. The main function of this class is to load or refresh the current configuration information. If a Spring container already exists, first destroy the Spring container, recreate the Spring container, load the bean definition, and complete the initialization of the container. It can be seen that the annotationconfigpplicationcontext container starts the whole Ioc container by calling the refresh method of its parent class AbstractApplicationContext to load and initialize the bean definition

1. Refresh preprocessing

AbstractApplicationContext.prepareRefresh()

protected void prepareRefresh() {
		// Switch to active.
		//Set container start time
		this.startupDate = System.currentTimeMillis();
		//Start identification
		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.
		//Empty method, used for the property setting method of custom personalization of child containers
		initPropertySources();

		// Validate that all properties marked as required are resolvable:
		// see ConfigurablePropertyResolver#setRequiredProperties
		//Check the validity of attributes, etc
		getEnvironment().validateRequiredProperties();

		// Store pre-refresh ApplicationListeners...
		// Early listeners to hold pre refreshed containers
		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...
		//Save early events in container
		this.earlyApplicationEvents = new LinkedHashSet<>();
	}

2. The subclass refreshes the internal BeanFactory and obtains the refreshed BeanFactory

AbstractApplicationContext.obtainBeanFactory()

/**
 * Tell the subclass to refresh the internal BeanFactory
 * Tell the subclass to refresh the internal bean factory.
 * @return the fresh BeanFactory instance
 * @see #refreshBeanFactory()
 * @see #getBeanFactory()
 */
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
   refreshBeanFactory();
   return getBeanFactory();
}

Gener icApplicationContext.refreshBeanFactory And getBeanFactory

protected final void refreshBeanFactory() throws IllegalStateException {
		//The atomic operation of AtomicBoolean is used to assign a value to the refreshed variable. During initialization, the refreshed value is false. If the assignment fails, an exception is thrown to avoid multiple refreshes
		if (!this.refreshed.compareAndSet(false, true)) {
			throw new IllegalStateException(
					"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
		}
		//Set the id unique id of the serialization id as annotationconfigpplicationcontext for BeanFactory
		this.beanFactory.setSerializationId(getId());
	}


	public final ConfigurableListableBeanFactory getBeanFactory() {
        //Return to DefaultListableBeanFactory
		return this.beanFactory;
	}

The steps to refresh BeanFactory are as follows:

1. Set the updated value of annotationconfiguapplicationcontext to true

2. Set the serializationId of DefaultBeanFactory to the id of annotationconfidapplicationcontext

 

3. Preprocessing of beanfactory

Mainly complete the property setting of BeanFactory

/**
* Complete the property setting of BeanFactory
*/
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		// Tell the internal bean factory to use the context's class loader etc.
		//Set bean classloader to container classloader for BeanFactory
		beanFactory.setBeanClassLoader(getClassLoader());
		//bean expression resolver
		beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
		//Property Edit registrar
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		// Configure the bean factory with context callbacks.
		//Configure beanFactory with context callback
		//Add a bean post processor to implement ApplicationContextAwareProcess
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
		//Set the ignored auto assembly interfaces, indicating that the implementation classes of these interfaces cannot be automatically injected through the interfaces
		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.
		//Register components that can be automatically assembled, and components that allow automatic injection in any component
		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.
		// Registering early PostProcessor with application listener to detect internal bean s
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

		// Detect a LoadTimeWeaver and prepare for weaving, if found.
		//Add AspectJ at compile time
		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.
		//Register the Singleton component, configurableenvironment, SystemProperties, systemenvironment in the container and add them to singletonObjects (ConcurrentHashMap type)
		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());
		}
	}

5. Execute the BeanFactoryPostProcess method, the postprocessor of beanfactory, after the beanfactory standard is initialized

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(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}
	}
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);
			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);
			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);
				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<>();
		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<>();
		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();
	}

 

Keywords: Spring REST Java xml

Added by nosmasu on Wed, 17 Jun 2020 07:06:03 +0300