This is the seventh day of my participation in the August More text Challenge. For details, see:August is more challenging

preface

The last article covered the beanFactory preprocessing in the Spring container initialization process. This article will sort out the post-processing of beanFactory.

In fact, there are many processes in the startup process of Spring, which is also very complex. I just sort it out according to my own ideas and understanding, and I will definitely ignore some things I think are not important or I have not found them. Also hope XDJMM can be more corrections.

The body of the

Dependent POM:

<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> < version > 5.2.8. RELEASE < / version > < / dependency >Copy the code

One of the processes that this article will cover is:

            / / classes and methods: AbstractApplicationContext# refresh
            // Allows post-processing of the bean factory in context subclasses.
            postProcessBeanFactory(beanFactory);
Copy the code

postProcessBeanFactory

PostProcessBeanFactory (); postProcessBeanFactory (); postProcessBeanFactory ();

   /**
    * Modify the application context's internal bean factory after its standard
    * initialization. All bean definitions will have been loaded, but no beans
    * will have been instantiated yet. This allows for registering special
    * BeanPostProcessors etc in certain ApplicationContext implementations.
    * @param beanFactory the bean factory used by the application context
    */
    // Modify the application context's internal beanFactory after the standard initialization of the beanFactory. All bean definitions are loaded, but the bean is not instantiated. Special registrations are allowed here
    // BeanPostProcessors in some ApplicationContext
Copy the code

Can know from the annotation, postProcessBeanFactory is to post processing of the BeanFactory, namely after the BeanFactory complete initialization to some changes, specific what to do, you do not see how a subclass to achieve it. Since I only imported the Spring-Context package, there is no implementation of this method, but you can see how it is implemented in a subclass in the SpringBoot project. It is important to note here that the version of SpringBoot I used is 2.5.2, and the code may vary from version to version. One of these subclasses is described below:

/ / classes and methods: AnnotationConfigServletWebServerApplicationContext# postProcessBeanFactory
   @Override
   protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
       // Call the parent class's postProcessBeanFactory method
      super.postProcessBeanFactory(beanFactory);
      // Execute scanner and Reader at this point and find that the second step has not been executed.
      if (this.basePackages ! =null && this.basePackages.length > 0) {
         this.scanner.scan(this.basePackages);
      }
      if (!this.annotatedClasses.isEmpty()) {
         this.reader.register(ClassUtils.toClassArray(this.annotatedClasses)); }}Copy the code

The parent class is ServletWebServerApplicationContext AnnotationConfigServletWebServerApplicationContext, Let’s see what the postProcessBeanFactory method looks like in the superclass.

/ / classes and methods: ServletWebServerApplicationContext# postProcessBeanFactory
   @Override
   protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
       // Register a PostProcessor with the BeanFactory
      beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));
        beanFactory.ignoreDependencyInterface(ServletContextAware.class);
        / / call registerWebApplicationScopes
        registerWebApplicationScopes();
   }
Copy the code

There are two main things that we do in a superclass method:

  1. To the BeanFactory registered a PostProcessor, registered a WebApplicationContextServletContextAwareProcessor
  2. RegisterWebApplicationScopes, the method name registration is the translation of web application scope.

WebApplicationContextServletContextAwareProcessor

Class:

/** * Variant of {@link ServletContextAwareProcessor} for use with a * {@link ConfigurableWebApplicationContext}. Can be  used when registering the processor * can occur before the {@link ServletContext} or {@link ServletConfig} have been * An initialized. * / / / for a ServletContextAwareProcessor ConfigurableWebApplicationContext extension, // You can register processors before initializing ServletContext or ServletConfig.Copy the code

Shows in the annotation is ServletContextAwareProcessor, then look at ServletContextAwareProcessor class comments:

/** * {@link org.springframework.beans.factory.config.BeanPostProcessor} * implementation that passes the ServletContext  to beans that implement * the {@link ServletContextAware} interface. * * <p>Web application contexts will automatically  register this with their * underlying bean factory. Applications do not use this directly. */ // Passing a ServletContext to a bean //Web application context that implements the ServletContextAware interface automatically registers it with the underlying bean factory. Applications will not use it directlyCopy the code

ServletContextAwareProcessor implements the BeanPostProcessor interface, So here is positioning to his postProcessBeforeInitialization method and postProcessAfterInitialization method

    @Override
   public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
      if(getServletContext() ! =null && bean instanceof ServletContextAware) {
         ((ServletContextAware) bean).setServletContext(getServletContext());
      }
      if(getServletConfig() ! =null && bean instanceof ServletConfigAware) {
         ((ServletConfigAware) bean).setServletConfig(getServletConfig());
      }
      return bean;
   }
   @Override
   public Object postProcessAfterInitialization(Object bean, String beanName) {
      return bean;
   }
Copy the code

The code is also simple, which is to determine whether the current bean is an implementation of ServletContextAware or ServletConfigAware, and then to invoke the implementation methods of each interface after the transformation. The implementation class for ServletContextAware is to call the setServletContext method. The implementation class for ServletConfigAware is to call the setServletConfig method.

Extensions: The BeanPostProcessor and XXXAware interfaces are involved here, the basic use of which will not be discussed here; The general process here is to register an implementation of BeanPostProcessor with the container, and then that implementation class is the method that handles the implementation class implementation of the XXXAware interface. In fact, you can also customize the extension of XXXAware interface according to this template, of course, you can also do some other processing, in short, BeanPostProcessor provides good scalability, here is just one of the ways.

registerWebApplicationScopes

This method registers the scope (“request”, “session”, “globalSession”, “application”) in the beanFactory.

The source code for this method is as follows:

/ / classes and methods: ServletWebServerApplicationContext# registerWebApplicationScopes
   private void registerWebApplicationScopes(a) {
          ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(getBeanFactory());
          WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory());
          existingScopes.restore();
    }
Copy the code

ExistingWebApplicationScopes ServletWebServerApplicationContext is a static class in class. The source code is as follows:

    public static class ExistingWebApplicationScopes {
        static {
         Set<String> scopes = new LinkedHashSet<>();
         scopes.add(WebApplicationContext.SCOPE_REQUEST);
         scopes.add(WebApplicationContext.SCOPE_SESSION);
         SCOPES = Collections.unmodifiableSet(scopes);
      }
        // This is the constructor, which basically takes the scope registered in the beanFactory and puts it in the SCOPES
        / / it is important to note that in the above method, the second line is registered in to the beanFactory, namely when the beanFactory inside without the request and the session the two scop
        // beanFactory assignment is complete. I suggest you interrupt to see it
      public ExistingWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) {
         this.beanFactory = beanFactory;
         for (String scopeName : SCOPES) {
            Scope scope = beanFactory.getRegisteredScope(scopeName);
            if(scope ! =null) {
               this.scopes.put(scopeName, scope); }}}// Since the above method has no values stored in the scopes, nothing will be executed here
      public void restore(a) {
         this.scopes.forEach((key, value) -> {
            if (logger.isInfoEnabled()) {
               logger.info("Restoring user defined scope " + key);
            }
            this.beanFactory.registerScope(key, value); }); }}Copy the code

WebApplicationContextUtils. RegisterWebApplicationScopes (), the method is to register the beanFactory web scope, source code is as follows:


    public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) {
      registerWebApplicationScopes(beanFactory, null);
   }
    public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory,
         @Nullable ServletContext sc) {
        
        // Register the scope
      beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());// Register request SCOP
      beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope());// Register session SCOP
      if(sc ! =null) {
         ServletContextScope appScope = new ServletContextScope(sc);
         beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope); // Register application SCOP
         // Register as ServletContext attribute, for ContextCleanupListener to detect it.
         sc.setAttribute(ServletContextScope.class.getName(), appScope);
      }
        // Add dependencies
      beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
      beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
      beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
      beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
      if(jsfPresent) { FacesDependencyRegistrar.registerFacesDependencies(beanFactory); }}Copy the code

This method is also relatively simple, mainly registered several registered domains request, session, application.

The last

At this point, org. Springframework. Context. Support. AbstractApplicationContext. PostProcessBeanFactory about process is finished in this method, this method is mainly do two things:

  1. Registered WebApplicationContextServletContextAwareProcessor, with the container handling ServletContextAware and ServletConfigAware implementation class
  2. Register scope, Request, session, application