SpringIOC Source Analysis

Keywords: Java Spring Back-end

  • Life cycle of bean s
  • Circular Dependency
  • Level 3 Cache
  • factorybena and benafactoey
  • Differences between appliaationcontext and beanfactory
  • ioc container

 

bean - Data Structure - map - Level 3 Cache

IOC container

context.getBean() - When to call

How to create a bean - factory, reflection - configuration file (xml) in a container

Introduction to Spring

Spring is a framework for controlling inversion, and IOC is achieved through injection dependency. Other implementations of dependent inversion are JNDI, and Spring has two main container families, BeanFactory and ApplicationContext, in which BeanFactory only implements the basic functions of containers (for example), while specifying the basic functional specifications of Bean containers. ApplicationContext is the advanced form of containers, which adds many frame-oriented features, such as -...

Spring uses BeanDefinition to manage abstract definitions of beans based on beans and their dependencies.

The difference between Benafanctory and ApplicationContext - BeanFactory only provides the most basic features and functions of the Ioc container. ApplicationContext adds many advanced features based on the extension of BeanFactory, which requires messages, internationalization, event publishing, etc.

Design interface diagram for SpringIoc container:

Analysis-

This design route for Configurable BeanFactory is the BeanFactory design route, which defines the basic IoC container specifications, such as getBean() basic methods; DefautlListableBeanFactory is the implementation of ConfigurableBeanFactory;

The ApplicationContext refines BeanFactory's functionality and extends some advanced features.

Specific implementation classes are - DefaultListableBeanFactory,XMLBeanFactory,ApplicationContext;

Use &Get FactoryBean itself, such as MyOnlyObject is a FactoryBean, use &MyOnlyObject to get FactoryBean itself, not a Bean object generated by this FactoryBean;

BeanFactory Design Details

getBean() - Gets a bean, indexed by the specified name (the actual beans are stored in the map;); At the same time, various getBean() methods with parameters are defined for type matching, etc.

containsBean() - Contains

isSingleton()-

isPrototype()-

isTypeMatch()-

getType()-

getAliases() - Get Aliases

XMLBeanFactroy analysis

XMLBeanfactory Class Diagram - XMLBeanfactory inherits the DefaultListableBeanFactory, and at the top is the implementation of the ConfigurableBeanFactory interface.

In Spring, DefaultListableBeanFactory is used as a default implementation of a fully functional BeanFactory;

The XMLBeanFactory reads the configuration information of the bean s through the XmlBeanDefinitionReader, and the XML file of the configuration information is abstracted through the Resource object;- Decoupling design

The Resource object is then passed as a construction parameter to the constructor of the BeanFactory;

Initialization of IOC Containers

Simply put, the initialization of IOC containers is done with the refresh() method; This process includes three basic processes: locating Recourse, loading and registering.

Spring separates these three basic processes and uses different modules to complete them. ResourceLoader,BeanDefinitionReader;

The first process is Resource Location, which is done by ResourceLoader through a unified Resource interface.

The second process is loading BeanDefinition:

The third process is to register a defined bean with the IOC container - through the implementation of the BeanDefinitionRegistry interface, injecting the BeanDefinition into a hashMap;

Initialization of containers does not include dependent injection processes; Dependent injection occurs the first time a getBean() is used to obtain a bean from a container; However, if the lazyinit property is set in the Bean Definition Information, the dependency injection will be completed at initialization time;

Dependent Injection of IOC Containers

The injection-dependent process occurs in the getBean() method, specifically by calling the doGetBean() method, in doGetBean(),

protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {

		String beanName = transformedBeanName(name);
		Object beanInstance;

		// Get the beans from the cache first, get the single beans that things have already been created. Requests for such beans do not need to be created repeatedly
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			if (logger.isTraceEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
//This completes the processing of FactoryBean.
			beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		else {
			// Fail if we're already creating this bean instance:
			// We're assumably within a circular reference.
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			// This checks the existence of BeanDefinition in the IOC container to see if the desired Bean is available in the current container or, if not, in the parent factory, to look up the parent chain
			BeanFactory parentBeanFactory = getParentBeanFactory();
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// Not found -> check parent.
				String nameToLookup = originalBeanName(name);
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				else if (args != null) {
					// Delegation to parent with explicit args.
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else if (requiredType != null) {
					// No args -> delegate to standard getBean method.
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
				else {
					return (T) parentBeanFactory.getBean(nameToLookup);
				}
			}

			if (!typeCheckOnly) {
				markBeanAsCreated(beanName);
			}
//Get BeanDefinition from beanName here
			StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
					.tag("beanName", name);
			try {
				if (requiredType != null) {
					beanCreation.tag("beanType", requiredType::toString);
				}

				RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);

				//Getting all dependent beans of the current bean triggers a recursive call to getBean(); Until you get a bean that has no dependencies;
				String[] dependsOn = mbd.getDependsOn();
				if (dependsOn != null) {
					for (String dep : dependsOn) {
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						registerDependentBean(dep, beanName);
						try {
//Recursive call to getBean()
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}

				// Here, a single-mode bean is created by calling the createBean() method; Here is a callback function getObject() that calls createBean() of ObjectFactory() in getSingleton;
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							destroySingleton(beanName);
							throw ex;
						}
					});
					beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
//Where prototype bean s are created;
				else if (mbd.isPrototype()) {
					// It's a prototype -> create a new instance.
					Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
					beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}

				else {
					String scopeName = mbd.getScope();
					if (!StringUtils.hasLength(scopeName)) {
						throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
					}
					Scope scope = this.scopes.get(scopeName);
					if (scope == null) {
						throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
					}
					try {
						Object scopedInstance = scope.get(beanName, () -> {
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							}
							finally {
								afterPrototypeCreation(beanName);
							}
						});
						beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
					}
					catch (IllegalStateException ex) {
						throw new ScopeNotActiveException(beanName, scopeName, ex);
					}
				}
			}
			catch (BeansException ex) {
				beanCreation.tag("exception", ex.getClass().toString());
				beanCreation.tag("message", String.valueOf(ex.getMessage()));
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
			finally {
				beanCreation.end();
			}
		}

		return adaptBeanInstance(name, beanInstance, requiredType);
	}

For the use of IOC containers, Spring provides a number of parameter configurations, each of which actually represents the implementation features of an IOC container, many of which are accomplished in the process of managing the Bean lifecycle, although the IOC container can be described in the simplest way as a hashMap. However, it can only be said that this hashMap is the most basic data structure of the container, not the entire IOC container. The value of the SPring IOC container as a framework is reflected in a series of related framework features that are centralized by inversion-dependent pattern implementations.

Detailed dependency injection process - getBean is the starting point of dependency injection; createBean is then called, in which case the beans are generated according to the requirements defined by the BeanDefinition. createBean() generates beans while initializing beans; For example, a post processor that defines a bean (AOP is implemented in this process)

How Spring loads configuration files into applications:

New classpath xmlapplocationContext ("beans.xml") - different configuration files - defines the specification interface for reading configuration files - yml, propetties,json,xml - definition information for beans

Read Definition Information - BeanDefinitionReader - Definition File Reader - Interface, corresponding to different implementations;

Resolution-

Instantiated Beans - The difference between instantiation and initialization - (new_() and _inti_() in python)

refresh() method in container benafactory--

prepareRefresh()

createBeanFactory()-new defaultListableBeanFactory()

Three ways to get a Class object in reflection--Class.forname() object.getClass() class.Class()

PostOrocessor - Post Processor - Extended Function - beanfactorypostprcessor

AOP - implemented in the bbefore and after methods of BeanPostProcessor;

Initialization of SpringIOC Container ------------------

new ClassPathXmlApplicationContext()-

super

 public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
        super(parent);
        this.setConfigLocations(configLocations);
        if (refresh) {
            this.refresh();
        }

    }

Posted by Digimatt on Thu, 11 Nov 2021 09:22:37 -0800