5. Extension of Container Function in Spring Source Analysis 5

Keywords: Programming Spring xml Attribute

1,ApplicationContext

ApplicationContext ctx = new ClassPathXmlApplicationContext("beanFactory.xml");

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
   this(new String[] {configLocation}, true, null);
}
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
                                                                                            throws BeansException {

   super(parent);
   setConfigLocations(configLocations);
   if (refresh) {
      refresh();
   }
}
public void setConfigLocations(String[] locations) {
   if (locations != null) {
      this.configLocations = new String[locations.length];
      for (int i = 0; i < locations.length; i++) {
           //Resolve the profile address and record it
           this.configLocations[i] = resolvePath(locations[i]).trim();
      }
   }
   else {
      this.configLocations = null;
   }
}

2. Extended Functions

if (refresh) {
   refresh();
}

//Almost all the core functions of Application Context are implemented in this method, and the logic is clear and clear.
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {

      //1. Prepare to refresh the context, such as initialization and validation of system attributes and environment variables.
      prepareRefresh();
      //2. Initialize BeanFactory and read the XML file
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
      //3. Fill in BeanFactory with various functions
      prepareBeanFactory(beanFactory);

      try {
         //Empty implementation, left to subclass extension
         postProcessBeanFactory(beanFactory);

         //4. Activate various BeanFactory processors
         invokeBeanFactoryPostProcessors(beanFactory);

         //5. Register BeanPostProcessor, which is just registration. The real call is at getBean time.
         registerBeanPostProcessors(beanFactory);

         //6. Initialize Message Source for Context, Internationalize Processing
         initMessageSource();

         //7. Initialize application message broadcasting and put it into application Event Multicaster
         initApplicationEventMulticaster();

         //Empty implementations, leaving subclass implementations to initialize other bean s
         onRefresh();

         //8. Find Listener bean s in all registered beans and register them in the broadcast
         registerListeners();

         //9. Initialization of non-delayed loading singletons
         finishBeanFactoryInitialization(beanFactory);

         //10. Complete the refresh process, notify the life processor of the refresh process, and issue ContextRefreshEvent to notify others
         finishRefresh();
      }
   }
}

Step 1: Prepare to refresh the context

//Preparations, such as initialization and validation of system attributes and environment variables
protected void prepareRefresh() {
   this.startupDate = System.currentTimeMillis();

   synchronized (this.activeMonitor) {
      this.active = true;
   }
   //Empty implementation, leaving subclass coverage
   initPropertySources();
   //Verify that all required properties files have been put into the environment
   getEnvironment().validateRequiredProperties();
}

Step 2: Load BeanFactory

//After this function, ApplicationContext has all the functions of BeanFactory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
   //Initialize the BeanFactory, read the XML file, and record the resulting beanFactory for later retrieval.
   refreshBeanFactory();

   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   return beanFactory;
}
@Override
protected final void refreshBeanFactory() throws BeansException {
   try {
      //Direct new DefaultListable BeanFactory
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      beanFactory.setSerializationId(getId());
      //Customized BeanFactory, where an extension of BeanFactory has begun
      customizeBeanFactory(beanFactory);
      //Load BeanDefinition
      loadBeanDefinitions(beanFactory);
      synchronized (this.beanFactoryMonitor) {
         //Recording beanFactory
         this.beanFactory = beanFactory;
      }
   }
}
//Customized BeanFactory, where an extension of BeanFactory has begun
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
   //Sets whether to allow objects with different definitions of the same name to be overwritten
   if (this.allowBeanDefinitionOverriding != null) {
       beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
   }
   //Setting whether to allow cyclic dependencies between bean s
   if (this.allowCircularReferences != null) {
       beanFactory.setAllowCircularReferences(this.allowCircularReferences);
   }
   //Support for @Qualifier and @Autowire annotations is provided
   beanFactory.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
}
//Load BeanDefinition
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory){
   //Create XmlBean Definition Reader to read the XML configuration file
   XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

   //Setting environment variables for XmlBean Definition Reader
   beanDefinitionReader.setEnvironment(this.getEnvironment());
   beanDefinitionReader.setResourceLoader(this);
   beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

   initBeanDefinitionReader(beanDefinitionReader);
   //After that, the following logic is the same as the read configuration file in BeanFactory.
   loadBeanDefinitions(beanDefinitionReader);
}

Step 3: Fill in BeanFactory with various functions

prepareBeanFactory(beanFactory);

//Spring completed the configuration analysis before entering the function prepareBeanFactory, and the functional extension of ApplicationContext expanded here.
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   beanFactory.setBeanClassLoader(getClassLoader());
   
   //Setting up the SpEL processor for the expression language of the bean Factory, Spring 3 adds support for the expression language.
   beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver());

   //Add a default property editor for beanFactory to parse Date (type 2018-07-27) in the configuration file
   beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

   //5.1 Add the ApplicationContext Aware Processor processor, as shown in the following analysis
   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

   //It was analyzed at 5.1, and the dependency was ignored here.
    beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
   beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
   beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
   //Some of the code was deleted later.
}

5.1. Adding Application Context Aware Processor Processor Processor

//Application Context Aware Processor implements BeanPostProcessor, which we analyzed in the Initial Bean of Spring Source Analysis 4. Spring activates init-method
//Before and after, BeanPostProcessor's before and after methods are invoked. Let's take a look at the two methods of ApplicationContextAware Processor that return directly without processing.
public Object postProcessAfterInitialization(Object bean, String beanName) {
   return bean;
}
public Object postProcessBeforeInitialization(final Object bean, String beanName){
   //Delete part of the code and leave the core code
   invokeAwareInterfaces(bean);
   return bean;
}
//After the bean s that implement these interfaces are initialized, the corresponding resources can be obtained, and the corresponding properties have been set on this side, so dependency notes need to be made in Spring.
//Ignore them when entering, as shown in the following code
private void invokeAwareInterfaces(Object bean) {
   if (bean instanceof Aware) {
      if (bean instanceof EnvironmentAware) {
         ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
      }
      if (bean instanceof EmbeddedValueResolverAware) {
         ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(
               new EmbeddedValueResolver(this.applicationContext.getBeanFactory()));
      }
      if (bean instanceof ResourceLoaderAware) {
         ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
      }
      if (bean instanceof ApplicationEventPublisherAware) {
         ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
      }
      if (bean instanceof MessageSourceAware) {
         ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
      }
      if (bean instanceof ApplicationContextAware) {
         ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
      }
   }
}

Step 4: Activate various BeanFactory processors

Note that BeanFactoryPostProcessor, not BeanPostProcessor. The BeanFactoryPostProcessor interface is similar to BeanPostProcessor in that it defines bean s.
For processing, the Spring IOC container allows BeanFactoryPostProcessor to read configuration metadata and modify it before the container instantiates any other bean s. Ordered connection can be implemented
 Port to set the execution order of BeanFactoryPostProcessor. Typical application of BeanFactoryPostProcessor: Property Placeholder Configurer. 
Property Placeholder Configurer indirectly inherits the BeanFactoryPostProcessor interface, and when Spring loads any configuration of beans that implement this interface, it will be in beans.
After the factory loads all the bean configurations, it executes the postProcessBeanFactory method. The postProcessBeanFactory method is implemented in Property Resource Configurer.
It is through the implementation of the BeanFactoryPostProcessor interface that the configuration is converted to the appropriate type and the configuration content is finally told to BeanFactory.
BeanFactory retrieves configuration information before instantiating any bean, so it can correctly parse variable references in the bean description file.
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
   //To be added
}

Step 5: Register BeanPost Processor

// This is just registration, not invocation. The real invocation is done in the bean instantiation stage. BeanFactory does not realize automatic registration of post-processor. It needs manual registration, but
 // Implementation of automatic registration function in Application Context
registerBeanPostProcessors(beanFactory);
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
   //Get the id names of all bean s configured in the configuration file that implement the BeanPostProcessor interface
   String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

   int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
   beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
   //High priority
   List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
   List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>();
   //Sorted
   List<String> orderedPostProcessorNames = new ArrayList<String>();
   //Disordered
   List<String> nonOrderedPostProcessorNames = new ArrayList<String>();

   for (String ppName : postProcessorNames) {
      if (isTypeMatch(ppName, PriorityOrdered.class)) {
         BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
         priorityOrderedPostProcessors.add(pp);
         if (pp instanceof MergedBeanDefinitionPostProcessor) {
            internalPostProcessors.add(pp);
         }
      }
      else if (isTypeMatch(ppName, Ordered.class)) {
         orderedPostProcessorNames.add(ppName);
      }
      else {
         nonOrderedPostProcessorNames.add(ppName);
      }
   }
   //Priority sorting and registration
   OrderComparator.sort(priorityOrderedPostProcessors);
   registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

   List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
   for (String ppName : orderedPostProcessorNames) {
      BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
      orderedPostProcessors.add(pp);
      if (pp instanceof MergedBeanDefinitionPostProcessor) {
         internalPostProcessors.add(pp);
      }
   }
   
   //Sort and register sorting
   OrderComparator.sort(orderedPostProcessors);
   registerBeanPostProcessors(beanFactory, orderedPostProcessors);

   List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
   for (String ppName : nonOrderedPostProcessorNames) {
      BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
      nonOrderedPostProcessors.add(pp);
      if (pp instanceof MergedBeanDefinitionPostProcessor) {
         internalPostProcessors.add(pp);
      }
   }
   
   //Registration of disorders
   registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

   OrderComparator.sort(internalPostProcessors);
   registerBeanPostProcessors(beanFactory, internalPostProcessors);

   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector());
}
private void registerBeanPostProcessors(
      ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
   for (BeanPostProcessor postProcessor : postProcessors) {
      beanFactory.addBeanPostProcessor(postProcessor);
   }
}
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
   //Deletion first ensures the uniqueness of the beanPostProcessor. In fact, the beanPostProcessors attribute is used to record the beanPostProcessor.
   this.beanPostProcessors.remove(beanPostProcessor);
   this.beanPostProcessors.add(beanPostProcessor);
   if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
      this.hasInstantiationAwareBeanPostProcessors = true;
   }
   if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
      this.hasDestructionAwareBeanPostProcessors = true;
   }
}

List<BeanPostProcessor> beanPostProcessors = new ArrayList<BeanPostProcessor>();

Step 6: Initialize Message Source for Context and Internationalize Processing

initMessageSource();

protected void initMessageSource() {
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   //If messageSource is configured in the container, this property is hardcoded
   if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
      this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
   }
   else {
      //If not configured, a temporary new MessageSource
      DelegatingMessageSource dms = new DelegatingMessageSource();
      dms.setParentMessageSource(getInternalParentMessageSource());
      this.messageSource = dms;
      //Register in Container
      beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
   }
}

Step 7: Initialize application message broadcasting and put it into application Event Multicaster

initApplicationEventMulticaster();
protected void initApplicationEventMulticaster() {
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   //If user-defined, use user-defined
   if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
      this.applicationEventMulticaster =
            beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
   }
   else {
      //Otherwise, use the default Application Event Multicaster
      this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
      beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
   }
}

Step 8: Find Listener bean s in all registered beans and register them in the broadcast

registerListeners();

protected void registerListeners() {
   
   for (ApplicationListener<?> listener : getApplicationListeners()) {
      getApplicationEventMulticaster().addApplicationListener(listener);
   }
   //Monitor Processor for Configuration File Registration
   String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
   for (String lisName : listenerBeanNames) {
      getApplicationEventMulticaster().addApplicationListenerBean(lisName);
   }
}

Step 9: Initialize the non-delayed loading singleton

finishBeanFactoryInitialization(beanFactory);

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
   //Configuring Conversion Service is also a type converter
   if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
         beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
      beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
   }
   //Freeze configuration, freeze all bean definitions, indicating that registered bean definitions will not be modified or processed further
   beanFactory.freezeConfiguration();
   //Initialize non-delayed loading, and the default behavior of ApplicationContext is to instantiate all non-delayed loading instances ahead of time at startup
   beanFactory.preInstantiateSingletons();
}
public void preInstantiateSingletons() throws BeansException {
   List<String> beanNames;
   synchronized (this.beanDefinitionMap) {
      beanNames = new ArrayList<String>(this.beanDefinitionNames);
   }
   for (String beanName : beanNames) {
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
      //Non-abstract, singleton, non-delayed loading
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
         if (isFactoryBean(beanName)) {
            final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
            boolean isEagerInit = (factory instanceof SmartFactoryBean &&
                                      ((SmartFactoryBean<?>) factory).isEagerInit());
            if (isEagerInit) {
               getBean(beanName);
            }
         }
         else {
            //Initialize bean s
            getBean(beanName);
         }
      }
   }
}

Step 10: Complete the refresh process

//Notify the life processor refresh process and issue ContextRefreshEvent to notify others
finishRefresh();

protected void finishRefresh() {
   //Initialize Lifecycle Processor
   initLifecycleProcessor();

   //Start all bean s that implement the Lifecycle interface
   getLifecycleProcessor().onRefresh();

   //Send the ContextRefreshedEvent event to ensure that the corresponding listener can do further processing
   publishEvent(new ContextRefreshedEvent(this));
}

Posted by skypilot on Wed, 09 Oct 2019 23:49:11 -0700