1. The Creation of Containers

By quickly building a spring-based web application with idea, we can start with the spring listener in web.xml

1.1 context Creation

When tomcat starts a webapp application, it uses multithreading to call the start method of StandardContext, and when StandarContext starts, it calls the listener that implements the ServletContextListener, from which spring container creation begins

public void contextInitialized(ServletContextEvent event) {
    //(1) Initialization of web application context
	initWebApplicationContext(event.getServletContext());
}

//(1) Initialization of web application context
public WebApplicationContext org.springframework.web.context.ContextLoader.initWebApplicationContext(ServletContext servletContext) {
//No reloading is allowed if it already exists		
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
			throw new IllegalStateException(
					"Cannot initialize context because there is already a root application context present - " +
					"check whether you have multiple ContextLoader* definitions in your web.xml!");
		}

		Log logger = LogFactory.getLog(ContextLoader.class);
		servletContext.log("Initializing Spring root WebApplicationContext");
		if (logger.isInfoEnabled()) {
			logger.info("Root WebApplicationContext: initialization started");
		}
		long startTime = System.currentTimeMillis();

		try {
			// Store context in local instance variable, to guarantee that
			// it is available on ServletContext shutdown.
			if (this.context == null) {
//The implementation of this application context can be specified in web.xml with contextClass
//If not specified, the application context in the configuration file is loaded by default. Here is the
//Xml Web Application Context, and must be Configurable Web Application Context
				//Type, because loading configuration is required, this interface defines how to load configuration
this.context = createWebApplicationContext(servletContext);
			}
			if (this.context instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
//This activity is set to true when refresh, indicating that the container has been activated and that the parent container has been loaded (activation can be used as an indication of whether to set the parent container, id, and even other functions that will be extended later)
				if (!cwac.isActive()) {
					// The context has not yet been refreshed -> provide services such as
					// setting the parent context, setting the application context id, etc
					if (cwac.getParent() == null) {
						// The context instance was injected without an explicit parent ->
						// determine parent for root web application context, if any.
                        //(2) Loading parent capacity
						ApplicationContext parent = loadParentContext(servletContext);
						cwac.setParent(parent);
					}
					configureAndRefreshWebApplicationContext(cwac, servletContext);
				}
			}
			//Setting the created context to the application context, we can get the context from the ServletContext.
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

		//... omit part of the code
	}
	
	

Since we did not specify contextClass in web.xml, we created a default Xml Web Application Context above. The context we will use in the future is an example of this class, so it is necessary to understand the inheritance structure of this class in order to have a better understanding of it.

ResourceLoader (interface for loading resources, such as configuration files)

Default Resource Loader

Disposable Bean (defines how to destroy a bean)

Lifecycle (Defining Life Cycle Capability, start, stop, is Runing)

Closeable (Defining the ability to close resources)

Environment Capable

Resource PatternResolver

Application Event Publisher (Defining the Ability to Publish Events)

Hierarchical BeanFactory (Defining the ability to acquire parent factory bean s)

Listable BeanFactory

MessageSource (Defining the ability to access international information)

Web Application Context (defines the ability to obtain ServletContext and defines a series of scope constants)

Environment (inherited from Property Resolver, providing parsing placeholders and obtaining values for corresponding properties)

Application Context (mainly defines the ability to acquire configurable Bean factories)

Configurable Application Context (configurable to provide extensible functionality, such as adding BeanFactoryPostProcessor to modify BeanDefinition or add BeanDefinition after loading configuration files)

Configurable Web Application Context (Provides the ability to acquire and configure configurations)

AbstractRefreshable Web Application Context (providing the ability to refresh and retrieve servletContext)

AbstractApplicationContext (template class, refersh method provided)

AbstractRefreshable Application Context (Defines whether Bean Definition is allowed to overload, whether circular dependency is allowed, holds enumerable BeanFactory, implements the same Listable BeanFactory, belongs to the decorator mode, has the ability to refresh containers, that is, restart containers)

AbstractRefreshable Config Application Context

BeanFactroy (interface, basic getBean functions)

Theme Source

Aware (Markup Interface for Notifying spring Containers for Some Callback Functions)

BeanName Aware (with the ability to set up BeanName)

Initializing Bean (Initializing capability, called after spring property injection, which is mainly used when context is used as bean injection)

Xml Web Application Context (Provides the ability to get loaded BeanDefinition from xml)

1.2 Creation of Father context

//(2) If the current container is not activated and the parent container is not set, try loading the parent container.
protected ApplicationContext org.springframework.web.context.ContextLoader.loadParentContext.loadParentContext(ServletContext servletContext) {
		ApplicationContext parentContext = null;
//LOCATOR_FACTORY_SELECTOR_PARAM   locatorFactorySelector  
//Get the profile address from the web.xml configuration
		String locatorFactorySelector = servletContext.getInitParameter(LOCATOR_FACTORY_SELECTOR_PARAM);
//LOCATOR_FACTORY_KEY_PARAM  parentContextKey
//The key of the parent container, which retrieves the corresponding key from the container specified by the locatorFactorySelector
		String parentContextKey = servletContext.getInitParameter(LOCATOR_FACTORY_KEY_PARAM);

		if (parentContextKey != null) {
			// locatorFactorySelector may be null, indicating the default "classpath*:beanRefContext.xml"
            //(3) If the locatorFactorySelector is empty, use the default configuration address classpath*: bean RefContext. XML
			BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector);
			Log logger = LogFactory.getLog(ContextLoader.class);
			if (logger.isDebugEnabled()) {
				logger.debug("Getting parent context definition: using parent context key of '" +
						parentContextKey + "' with BeanFactoryLocator");
			}
            //(4)
			this.parentContextRef = locator.useBeanFactory(parentContextKey);
			parentContext = (ApplicationContext) this.parentContextRef.getFactory();
		}

		return parentContext;
	}
	
	
//(3)
public static BeanFactoryLocator org.springframework.context.access.ContextSingletonBeanFactoryLocator.getInstance(String selector) throws BeansException {
		//Resource Address
String resourceLocation = selector;
		if (resourceLocation == null) {
			resourceLocation = DEFAULT_RESOURCE_LOCATION;
		}

		// For backwards compatibility, we prepend "classpath*:" to the selector name if there
		// is no other prefix (i.e. "classpath*:", "classpath:", or some URL prefix).
		if (!ResourcePatternUtils.isUrl(resourceLocation)) {
			resourceLocation = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resourceLocation;
		}

		synchronized (instances) {
			if (logger.isTraceEnabled()) {
				logger.trace("ContextSingletonBeanFactoryLocator.getInstance(): instances.hashCode=" +
						instances.hashCode() + ", instances=" + instances);
			}
            //Loading Bean Factory Locator from Cache
			BeanFactoryLocator bfl = instances.get(resourceLocation);
			if (bfl == null) {
				bfl = new ContextSingletonBeanFactoryLocator(resourceLocation);
				instances.put(resourceLocation, bfl);
			}
			return bfl;
		}
	}


(4)ContextSingletonBeanFactoryLocator
public BeanFactoryReference useBeanFactory(String factoryKey) throws BeansException {
		synchronized (this.bfgInstancesByKey) {
//Get the beanfactory group from the cache. The so-called beanfactory group is the container that holds a series of beanFactory.
			BeanFactoryGroup bfg = this.bfgInstancesByKey.get(this.resourceLocation);
//If it is not empty, then the bean project will set up a sub-container, then the reference count plus one
			if (bfg != null) {
				bfg.refCount++;
			}
			else {
				// This group definition doesn't exist, we need to try to load it.
				if (logger.isTraceEnabled()) {
					logger.trace("Factory group with resource name [" + this.resourceLocation +
							"] requested. Creating new instance.");
				}

				// Create the BeanFactory but don't initialize it.
//Create a ClassPathXml Application Context container group without initialization
/**
protected BeanFactory createDefinition(String resourceLocation, String factoryKey) {
		return new ClassPathXmlApplicationContext(new String[] {resourceLocation}, false);
	}
**/
				BeanFactory groupContext = createDefinition(this.resourceLocation, factoryKey);

				// Record its existence now, before instantiating any singletons.
//Record this context to a BeanFactory Group and use refCount to record the number of times it has been applied
				bfg = new BeanFactoryGroup();
				bfg.definition = groupContext;
				bfg.refCount = 1;
				//Recorded in the cache
				this.bfgInstancesByKey.put(this.resourceLocation, bfg);
				this.bfgInstancesByObj.put(groupContext, bfg);

			    //
				try {
//Since we created the ClassPath Xml Application Context to implement Configurable Application Context, we call refresh() directly here for initialization and other operations.
					initializeDefinition(groupContext);
				}
				catch (BeansException ex) {
					this.bfgInstancesByKey.remove(this.resourceLocation);
					this.bfgInstancesByObj.remove(groupContext);
					throw new BootstrapException("Unable to initialize group definition. " +
							"Group resource name [" + this.resourceLocation + "], factory key [" + factoryKey + "]", ex);
				}
			}

			try {
				BeanFactory beanFactory;
				//Get the specified type of container from the container group you just created
				if (factoryKey != null) {
				
					beanFactory = bfg.definition.getBean(factoryKey, BeanFactory.class);
				}
				else {
					beanFactory = bfg.definition.getBean(BeanFactory.class);
				}
				//Create an instance that implements the BeanFactoryReference interface class
				//This interface has the ability to retrieve and release specified BeanFactory instances
				//The ability of BeanFactory, once the reference count becomes zero, then this
				//BeanFactory Group can be destroyed. (citation counting)
				return new CountingBeanFactoryReference(beanFactory, bfg.definition);
			}
			catch (BeansException ex) {
				throw new BootstrapException("Unable to return specified BeanFactory instance: factory key [" +
						factoryKey + "], from group with resource name [" + this.resourceLocation + "]", ex);
			}

		}
	}

When creating parent context, spring uses Classpath Xml Application Context, so what's the difference between this class and its child context? Let's look at its class diagram.

AbstractXml Application Context (Provides the ability to obtain and load configuration files)

Disposable Bean

The biggest difference between Classpath Xml Application Context and Xml Web Application Context is that Web Application Context is not implemented, that is to say, Classpath Xml Application Context does not have the ability to retrieve attribute resources and request, session, and global session life cycle from web context. He has similar abilities, so I won't study how ClassPath Xml Application Context is initialized here. We just need to know how Xml Web Application Context is initialized, so the initialization of the former is natural.

Next, take a look at the relational class diagrams of some of the classes involved in creating parent containers

BeanFactoryLocator (Defines the ability to obtain BeanFactory references)

BeanFactoryReference (Defines the ability to capture BeanFactory and release BeanFactory, reference count decreases, and destroy containers)

Singleton BeanFactoryLocator (implements BeanFactoryLocator and provides two static attributes)
BFG Instances ByKey: Resource Address - BeanFactory Group
BFG Instances ByObj: Specific Container Group - "BeanFactory Group"

)

ContextSingleton BeanFactoryLocator (successor to Singleton BeanFactoryLocator) provides a static variable instances to maintain the relationship between resources and BeanFactoryLocator
)

CountingBeanFactoryReference (implementer of BeanFactoryReference, holds the target BeanFactory and the container group to which the target BeanFactory belongs, through which the reference count of the container decreases or even the container is destroyed)

Drawing Tool IDEA and IBM Rational Rose

Tags: xml Spring Session Tomcat

Posted on Sat, 03 Aug 2019 23:57:08 -0700 by acidglitter