IOC

An overview of the

To understand the Spring feature IOC, we first need to clean up the IOC definition and source knowledge so that we can understand Spring at a higher level. Let’s take a step-by-step look at the implementation of Spring IOC through Spring’s responsibilities. So we start with the lifecycle of the container and the lifecycle of the managed resource, then processing between dependencies, and finally configuration.

What is the IOC

The IOC is an inversion of control. Whereas traditional software uses the application code to actively invoke the common code base to achieve the goal, inversion of control uses the framework to invoke the application code to achieve the goal.

The origin of the IOC

  • In 1983, Richard E. Sweet proposed The “Hollywood Principle” in The Mesa Programming Environment: The code we write tells The framework to make calls, Instead of the framework constantly asking if the application’s code is called.
  • In 1988, Ralph E. Johnson & Brian Foote in Designing Reusable Classes proposes “Inversion of Control” : Using the Hollywood Principles There are two ways to use Inversion of control for a framework
    • Using a white box framework, implemented using abstract classes of the framework, but there is a learning cost to understanding the white box framework
    • With a black-box framework, the application code is used as a component under the protocol specifications defined by the framework, so you just need to learn those protocol specifications
  • In 2004, Martin Fowler put forward his understanding of IoC and DI in Inversion of Control Containers and the Dependency Injection Pattern: Inversion of control is more specific about how to assemble the components. You need to deal with each part of each component.

The IOC’s responsibility

  • Life cycle management
    • Container lifecycle: For example, the Spring IOC container is up, running, and destroyed
    • Lifecycle of managed resources (Java Beans or other resources) : such as initialization, instantiation, and destruction of Spring Beans
  • Depend on the processing
    • Dependency injection: For example, direct dependency injection of Spring beans
    • Dependent lookup: For example, Spring Beans look up beans by their name
  • configuration
    • Container configuration: Such as initialization of the Spring container configuration
    • External configuration: For example, configuration required for database links
    • Configuration of managed resources (Java Beans or other resources) : Such as the definition of Spring Beans

The Spring IOC container

Key interface:

  • BeanFactory: An interface that provides the basic functionality of the IOC container
  • ApplicationContext: a subclass of BeanFactory that, in addition to providing the same methods as BeanFactory, provides AOP integration, message resource handling, event publishing, and application-specific contexts (such as the Web)

The Spring IOC container lifecycle

Do a simple introduction to the entrance first, then supplement

  • Start the

    //org.springframework.context.support.AbstractApplicationContext
    @Override
    	public void refresh(a) throws BeansException, IllegalStateException {
    		synchronized (this.startupShutdownMonitor) {
    			// Prepare this context for refreshing.
    			prepareRefresh();
    
    			// Tell the subclass to refresh the internal bean factory.
    			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
    			// Prepare the bean factory for use in this context.
    			prepareBeanFactory(beanFactory);
    
    			try {
    				// Allows post-processing of the bean factory in context subclasses.
    				postProcessBeanFactory(beanFactory);
    
    				// Invoke factory processors registered as beans in the context.
    				invokeBeanFactoryPostProcessors(beanFactory);
    
    				// Register bean processors that intercept bean creation.
    				registerBeanPostProcessors(beanFactory);
    
    				// Initialize message source for this context.
    				initMessageSource();
    
    				// Initialize event multicaster for this context.
    				initApplicationEventMulticaster();
    
    				// Initialize other special beans in specific context subclasses.
    				onRefresh();
    
    				// Check for listener beans and register them.
    				registerListeners();
    
    				// Instantiate all remaining (non-lazy-init) singletons.
    				finishBeanFactoryInitialization(beanFactory);
    
    				// Last step: publish corresponding 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(); }}}Copy the code
  • run

  • stop

    //org.springframework.context.support.AbstractApplicationContext	
    @Override
    	public void close(a) {
    		synchronized (this.startupShutdownMonitor) {
    			doClose();
    			// If we registered a JVM shutdown hook, we don't need it anymore now:
    			// We've already explicitly closed the context.
    			if (this.shutdownHook ! =null) {
    				try {
    					Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
    				}
    				catch (IllegalStateException ex) {
    					// ignore - VM is already shutting down}}}}Copy the code
    //org.springframework.context.support.AbstractApplicationContext
    protected void doClose(a) {
    		// Check whether an actual close attempt is necessary...
    		if (this.active.get() && this.closed.compareAndSet(false.true)) {
    			if (logger.isDebugEnabled()) {
    				logger.debug("Closing " + this);
    			}
    
    			LiveBeansView.unregisterApplicationContext(this);
    
    			try {
    				// Publish shutdown event.
    				publishEvent(new ContextClosedEvent(this));
    			}
    			catch (Throwable ex) {
    				logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
    			}
    
    			// Stop all Lifecycle beans, to avoid delays during individual destruction.
    			if (this.lifecycleProcessor ! =null) {
    				try {
    					this.lifecycleProcessor.onClose();
    				}
    				catch (Throwable ex) {
    					logger.warn("Exception thrown from LifecycleProcessor on context close", ex); }}// Destroy all cached singletons in the context's BeanFactory.
    			destroyBeans();
    
    			// Close the state of this context itself.
    			closeBeanFactory();
    
    			// Let subclasses do some final clean-up if they wish...
    			onClose();
    
    			// Reset local application listeners to pre-refresh state.
    			if (this.earlyApplicationListeners ! =null) {
    				this.applicationListeners.clear();
    				this.applicationListeners.addAll(this.earlyApplicationListeners);
    			}
    
    			// Switch to inactive.
    			this.active.set(false); }}Copy the code

Resources: time.geekbang.org/course/intr…