spring源码(三)beanFactory后置处理

910 阅读4分钟

这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战

前言

上一篇讲了spring容器初始化流程中的beanFactory预处理。那这一篇将对beanFactory的后置处理进行整理。

其实spring的启动过程是有很多流程的,也是很复杂的,我只是根据自己的思路和理解来进行整理的,肯定就会忽略一些自认为不重要的或者是自己没有发现的地方。也希望xdjmm能够多多指正。

正文

依赖的pom:

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

本篇文章将要说的一个流程就是:

            //所在类及方法: AbstractApplicationContext#refresh
            // Allows post-processing of the bean factory in context subclasses.
            postProcessBeanFactory(beanFactory);

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
    */
    // 在beanFactory完成标准的初始化后修改应用上下文的内部bean factory,所有的bean定义都会被加载,但是并不会实例化bean。这里允许注册特殊的
    // BeanPostProcessors 等在某些应用上下文中(ApplicationContext的实现)

从注释可以知道,postProcessBeanFactory就是对BeanFactory进行后置处理,也就是在BeanFactory完成初始化后可以对其进行一些修改,具体要做什么,就看子类怎么去实现的了。 由于我只导入了spring-context包,里面对该方法的实现是没有的,不过可以在springboot项目中去查看该方法在子类中是如何去实现的。 这里需要注意的是,我使用的springboot的版本是2.5.2,不同版本的代码可能是不一样的。 下面对其中的一个子类代码进行讲解:

// 所在类及方法:AnnotationConfigServletWebServerApplicationContext#postProcessBeanFactory
   @Override
   protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
       // 调用父类的postProcessBeanFactory方法
      super.postProcessBeanFactory(beanFactory);
      // 执行scanner和reader   在此地方打断点,发现第二步并没有执行。
      if (this.basePackages != null && this.basePackages.length > 0) {
         this.scanner.scan(this.basePackages);
      }
      if (!this.annotatedClasses.isEmpty()) {
         this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
      }
   }

AnnotationConfigServletWebServerApplicationContext的父类是ServletWebServerApplicationContext, 下面看看父类中的postProcessBeanFactory方法是怎么样的。

// 所在类及方法:ServletWebServerApplicationContext#postProcessBeanFactory
   @Override
   protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
       // 向BeanFactory中注册一个PostProcessor
      beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));
        beanFactory.ignoreDependencyInterface(ServletContextAware.class);
        // 调用registerWebApplicationScopes
        registerWebApplicationScopes();
   }

在父类的方法中主要就是做了两件事:

  1. 向BeanFactory中注册一个PostProcessor,也就是注册一个WebApplicationContextServletContextAwareProcessor
  2. registerWebApplicationScopes,把方法名翻译过来就是注册web应用的作用域。

WebApplicationContextServletContextAwareProcessor

类的注释:

    /**
     * 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
     * initialized.
     */
    // 用于ConfigurableWebApplicationContext的一个ServletContextAwareProcessor扩展,
    // 可以在初始化ServletContext或ServletConfig之前进行处理器的注册。

注解中说明了是ServletContextAwareProcessor,那么看看ServletContextAwareProcessor类的注释:

/**
 * {@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.
 */
//  将ServletContext传递给实现ServletContextAware接口的bean
//Web应用程序上下文将自动将其注册到底层bean工厂。应用程序不会直接使用它

ServletContextAwareProcessor实现了BeanPostProcessor接口, 那么这里就定位至他的postProcessBeforeInitialization方法和postProcessAfterInitialization方法

    @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;
   }

代码也比较简单,就是判断当前bean是ServletContextAware的实现还是ServletConfigAware的实现,然后分别转换后再调用各自接口的实现方法。 ServletContextAware的实现类就是调用setServletContext方法。 ServletConfigAware的实现类就是调用setServletConfig方法。

扩展: 这里涉及到了BeanPostProcessor和XXXAware接口,这两种接口的基本使用这里就不细说了; 这里的大概流程就是:向容器注册BeanPostProcessor的一个实现,然后该实现类是处理XXXAware接口的实现类实现的方法。 其实自己也可以根据这个模板来进行自定义XXXAware接口的扩展,当然也可以进行其他的一些处理,总之就是BeanPostProcessor提供了很好的扩展性,这里只是其中的一种方式。

registerWebApplicationScopes

这个方法主要就是向beanFactory中注册作用域:("request", "session", "globalSession", "application"),在源码分析:

该方法的源码如下:

// 所在类及方法:ServletWebServerApplicationContext#registerWebApplicationScopes
   private void registerWebApplicationScopes() {
          ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(getBeanFactory());
          WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory());
          existingScopes.restore();
    }

ExistingWebApplicationScopes是ServletWebServerApplicationContext类中的一个静态类。源码如下:

    public static class ExistingWebApplicationScopes {
        static {
         Set<String> scopes = new LinkedHashSet<>();
         scopes.add(WebApplicationContext.SCOPE_REQUEST);
         scopes.add(WebApplicationContext.SCOPE_SESSION);
         SCOPES = Collections.unmodifiableSet(scopes);
      }
        // 这是构造方法,大概就是根据SCOPES获取beanFactory中已经注册的scope,然后放入scopes
        // 需要注意的是,在上面的方法中,第二行才在向beanFactory中注册,也就是这时的beanFactory里面没有request和session这两个scop
        // 所以这里就完成了beanFactory的赋值。建议打断点进去看看
      public ExistingWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) {
         this.beanFactory = beanFactory;
         for (String scopeName : SCOPES) {
            Scope scope = beanFactory.getRegisteredScope(scopeName);
            if (scope != null) {
               this.scopes.put(scopeName, scope);
            }
         }
      }
        // 由于上面的方法并没有值存入scopes,所以这里也就没执行里面的内容
      public void restore() {
         this.scopes.forEach((key, value) -> {
            if (logger.isInfoEnabled()) {
               logger.info("Restoring user defined scope " + key);
            }
            this.beanFactory.registerScope(key, value);
         });
      }

   }

WebApplicationContextUtils.registerWebApplicationScopes(),这个方法就是向beanFactory注册web的scope了,源码如下:


    public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) {
      registerWebApplicationScopes(beanFactory, null);
   }
    public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory,
         @Nullable ServletContext sc) {
        
        // 注册作用域
      beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());// 注册request  SCOP
      beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope());// 注册session SCOP
      if (sc != null) {
         ServletContextScope appScope = new ServletContextScope(sc);
         beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope); // 注册application SCOP
         // Register as ServletContext attribute, for ContextCleanupListener to detect it.
         sc.setAttribute(ServletContextScope.class.getName(), appScope);
      }
        // 添加依赖项
      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);
      }
   }

这个方法也比较简单,主要注册了几种注册域request ,session ,application。

最后

至此,org.springframework.context.support.AbstractApplicationContext.postProcessBeanFactory 这个方法的大概流程就讲完了,这个方法主要就是做了两点:

  1. 向容器注册WebApplicationContextServletContextAwareProcessor,用来处理ServletContextAware和ServletConfigAware的实现类
  2. 注册作用域,request,session,application