spring源码(三)beanFactory后置处理

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

前言

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

其实spring的启动过程是有不少流程的,也是很复杂的,我只是根据本身的思路和理解来进行整理的,确定就会忽略一些自认为不重要的或者是本身没有发现的地方。也但愿xdjmm可以多多指正。spring

正文

依赖的pom:springboot

<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.8.RELEASE</version>
        </dependency>
复制代码

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

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

postProcessBeanFactory

进入postProcessBeanFactory方法,发现该方法是一个空方法,什么也没作,不过根据该方法的注释翻译:session

/** * 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,不一样版本的代码多是不同的。 下面对其中的一个子类代码进行讲解:app

// 所在类及方法: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方法是怎么样的。ide

// 所在类及方法: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

类的注释:post

/**
     * 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
相关文章
相关标签/搜索