“This is the sixth day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

1. Introduction to IOC containers

IoC(Inversion of Control) is also known as dependency injection (DI). This is a process in which objects define their dependencies (that is, other objects they use) only by constructor parameters, factory method parameters, or properties that are set on the object instance after the object instance is constructed or returned from the factory method. The container then injects these dependencies when the bean is created. This process is basically the inverse of the bean itself (hence the inversion of control), controlling the instantiation or location of its dependencies through mechanisms such as direct construction of classes or service locator patterns.

The org. Springframework. Beans and org. Springframework. Context packages are The basis for Spring Framework ‘s IoC container. The BeanFactory interface provides an advanced configuration mechanism capable of managing any type of object. ApplicationContext is a sub-interface of BeanFactory

: is the translation of the copy from the official website, org. Springframework. Beans and org., springframework. Context is the basis of the framework of the Spring IoC container. The BeanFactory interface provides an advanced configuration mechanism for managing any type of object. ApplicationContext is a subinterface of the BeanFactory.

That is, there are two main implementations of IOC containers. One is inherited from BeanFactory, and the other is inherited from ApplicationContext. BeanFactory provides the configuration framework and basic functions, while ApplicationContext provides more and richer functions.

2. How does it work

The principle diagram of the 2.1

From the structure diagram on the official website, we can easily see that the essence of a container is to manage business classes, read configuration files, and prepare a system that generates sufficient configuration for us

  • Here poJOs can be understood as our business class
  • Metadata is our configuration file, such as XML, configuration classes, etc

2.2 ApplicationContext code analysis

We used to see this code a lot when we were learning Spring.

ApplicationContext appContext = new ClassPathXmlApplicationContext("/**/beans.xml");
Person p = (Person)appContext.getBean("person");
Copy the code

Point into the ClassPathXmlApplicationContext, then open the inheritance relationship

We see that it inherits the class that implements the ApplicationContext interface. Click into the ApplicationContext class and you’ll see that it inherits many interfaces

public interface ApplicationContext extends EnvironmentCapable, 
                                            ListableBeanFactory, 
                                            HierarchicalBeanFactory,
                                            MessageSource,
                                            ApplicationEventPublisher,
                                            ResourcePatternResolver
Copy the code
  • EnvironmentCapable: All Spring application contexts support the environment and use interfaces primarily to perform type checking in framework methods that accept a BeanFactory
  • ListableBeanFactory: Implements the BeanFactory interface. Listable means available. ListableBeanFactory can enumerate all of their bean information without looking up the bean’s name or type one by one.
  • HierarchicalBeanFactory: Implements the HierarchicalBeanFactory interface and returns a value that takes no account of the hierarchy and only reads the information of the current container definition
  • MessageSource: Used to support internationalization of information and substitution of information containing parameters
  • ApplicationEventPublisher: publishing events, that is, an event to release information to tell all to monitor this event listeners.
  • ResourcePatternResolver: Interface for parsing Resource file policies. Inherits ResourceLoader to obtain resources

2.3 ClassPathXmlApplicationContext instantiation

1. Follow the code above and go directly to its constructor

Public ClassPathXmlApplicationContext (String configLocation) throws BeansException {/ / here find it calls another constructor, This (new String[] {configLocation}, true, null); } public ClassPathXmlApplicationContext( String[] configLocations, boolean refresh, @nullable ApplicationContext parent) throws BeansException {// Call the parent constructor super(parent); // Sets the configuration location for this application context. If not, the implementation may use the default as needed. setConfigLocations(configLocations); If (refresh) {core code refresh() method}}Copy the code

2. Look at the refresh() method, which is at the heart of container initialization!

public void refresh() throws BeansException, An IllegalStateException {synchronized (enclosing startupShutdownMonitor) {/ / 2.1 to refresh this container ready. prepareRefresh(); After this step is complete, the configuration file is parsed into bean definitions. // The BeanFactory is registered (but not initialized). Just write the information to the map beanDefination) ConfigurableListableBeanFactory the beanFactory = obtainFreshBeanFactory (); // 2.3 Prepare bean factories for use in this context. Configure the factory's standard context characteristics, such as the context's classloader and post-handler. prepareBeanFactory(beanFactory); Try {// 2.4 allows postprocessing of bean factories in context subclasses postProcessBeanFactory(beanFactory); / / 2.5 registered the BeanFactory post processor instantiate and call all registered the BeanFactory rear realization method of the class, must call before singleton instantiation invokeBeanFactoryPostProcessors (the BeanFactory);  // This interface has two methods: PostProcessBeforeInitialization and postProcessAfterInitialization / / two methods in the Bean initialization respectively before and after the initialization are implemented. Note that Bean here haven't initialize registerBeanPostProcessors (the beanFactory); //2.7 Internationalizing initMessageSource(); / / 2.8 initialization event multicast initApplicationEventMulticaster (); //2.9 Initialize other special beans in context subclasses onRefresh(); // Notice 2.11 Checking listeners and registerListeners(); / / 2.12 initialize all the lazy loading of single instance bean finishBeanFactoryInitialization (the beanFactory); FinishRefresh (); finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy the already established singleton bean to avoid wasting the resource destroyBeans(); // Set the active state false 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
2.1: The prepareRefresh() method is resolved
Protected void prepareRefresh() {// Set the boot time this.startupDate = system.currentTimemillis (); // Set the state this.closed. Set (false); // Set the activation state this.active. Set (true); Logger.isdebugenabled ()) {if (logger.istraceEnabled ()) {logger.trace("Refreshing "+ this); } else { logger.debug("Refreshing " + getDisplayName()); }} // Initializes any placeholder property source in the context initPropertySources(); / / verify whether all the necessary attributes can be parsed / / there must attribute is set up by using the approach of ConfigurablePropertyResolver setRequiredProperties getEnvironment().validateRequiredProperties(); / / refresh the listener status to pre refresh the if (this. EarlyApplicationListeners = = null) {enclosing 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... this.earlyApplicationEvents = new LinkedHashSet<>(); }Copy the code
2.2: obtainFreshBeanFactory ()
Protected ConfigurableListableBeanFactory obtainFreshBeanFactory () {/ / refresh the BeanFactory refreshBeanFactory (); // Return BeanFactory(); }Copy the code
  1. AbstractRefreshableApplicationContext refreshBeanFactory () method resolution for it (for example)
@override protected final void refreshBeanFactory() throws BeansException { Then close BeanFactory if (hasBeanFactory()) {destroyBeans(); closeBeanFactory(); } the try {/ / create a new the beanFactory DefaultListableBeanFactory the beanFactory = createBeanFactory (); / / set serializationId the beanFactory. SetSerializationId (getId ()); // customizeBeanFactory Settings to allow Bean definitions to be overridden and to allow circular references to customizeBeanFactory(beanFactory); // This method parses DOM documents (such as XML files) and generates BeanDefinition loadBeanDefinitions(beanFactory). synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); }}Copy the code

2. GetBeanFactory () returns is DefaultListableBeanFactory type by default.

@Nullable private DefaultListableBeanFactory beanFactory; @Override public final ConfigurableListableBeanFactory getBeanFactory() { synchronized (this.beanFactoryMonitor) { if (this.beanFactory == null) { throw new IllegalStateException("BeanFactory not initialized or already closed - " + "call 'refresh' before accessing beans via the ApplicationContext"); } return this.beanFactory; }}Copy the code
2.3 prepareBeanFactory (the beanFactory)
Protected void prepareBeanFactory (ConfigurableListableBeanFactory the beanFactory) {/ / set the class loader, if there is directly set in, If not Create a new default the beanFactory. SetBeanClassLoader (getClassLoader ()); // Specify the parsing strategy for the expressions in the bean definition value. By default, there is no active expression support in BeanFactory. //ApplicationContext usually sets the standard expression policy here, supporting "#{... } "expression. / / set the EL expression parser (Bean initialization complete filling properties will be used). The beanFactory setBeanExpressionResolver (new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); // Add the PropertyEditor property editor (we can dynamically set our property to the corresponding property type in the bean) // for example: Property is assigned to the pathname (classpath/spring.xml) and the corresponding bean property is set to Resource, // Spring frameworkbean propertyEditors package has many spring properties editor // The ResourceEditor is available in the IO package of spring Framework-core. The ResourceEditor can be customized by implementing the PropertyEditorSupport interface. Spring's built-in property editor does the same with ApplicationContext, which is registered with CustomEditorConfigurer in the configuration file. // CustomEditorConfigurer implements the BeanFactoryPostProcessor interface, so it is a Bean factory postprocessor. // It is executed after loading the configuration file in the Spring container and generating the BeanDefinition. beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); / / the object of the current ApplicationContext to ApplicationContextAwareProcessor class to deal with, / / to Aware the interface implementation class in the injection applicationContext. The beanFactory addBeanPostProcessor (new ApplicationContextAwareProcessor (this)); / / the following six attributes can be ignored, automatic assembly. The beanFactory ignoreDependencyInterface (EnvironmentAware. Class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); / / register several can parse, automatic assembly the beanFactory. Class and instances of registerResolvableDependency (the beanFactory. Class, the beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); / / add a BeanPostProcessor, it has two methods postProcessBeforeInitialization in bean initializes the former executive / / postProcessAfterInitialization in bean initializes the post-processing. ApplicationListenerDetector rewrite the postProcessAfterInitialization method the beanFactory. AddBeanPostProcessor (new ApplicationListenerDetector(this)); If (beanfactory.containsbean (LOAD_TIME_WEAVER_BEAN_NAME)) {// If (beanfactory.containsbean (LOAD_TIME_WEAVER_BEAN_NAME)) { Is to register a LoadTimeWeaverAwareProcessor to the beanFactory in the container. The addBeanPostProcessor (new LoadTimeWeaverAwareProcessor (the beanFactory)); / / create a temporary this to let the handle real bean the beanFactory. SetTempClassLoader (new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } // The following three parts mainly register the default environment bean 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()); }}Copy the code

The liver is not moving, so I will stop here for today. I will continue to analyze the remaining methods 2.4–2.13 in the subsequent articles.