购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

3.2 AnnotationConfigServletWebServerApplicationContext分析

本节将对AnnotationConfigServletWebServerApplicationContext进行分析,该对象是ConfigurableWebServerApplicationContext接口的实现类,接下来需要关注ConfigurableWebServerApplicationContext成员变量,详细见表3-2。

表3-2 ConfigurableWebServerApplicationContext成员变量

在AnnotationConfigServletWebServerApplicationContext中,除了成员变量外还需要关注构造方法,具体处理代码如下:

public AnnotationConfigServletWebServerApplicationContext(Class<?>... annotatedClasses) {
   this();
   register(annotatedClasses);
   refresh();
}
public AnnotationConfigServletWebServerApplicationContext(String... basePackages) {
    this();
    scan(basePackages);
    refresh();
}

在上述代码的两个构造函数中,主要进行成员变量reader和scanner的初始化,此外还会执行register和scan方法。接下来对register方法进行分析,具体处理代码如下:

    public final void register(Class<?>... annotatedClasses) {
         Assert.notEmpty(annotatedClasses, "At least one annotated class must be
specified");
        this.annotatedClasses.addAll(Arrays.asList(annotatedClasses));
    }

在register方法中会将参数annotatedClasses全部加入成员变量annotatedClasses中。接下来对scan方法进行分析,具体处理代码如下:

public final void scan(String... basePackages) {
   Assert.notEmpty(basePackages, "At least one base package must be specified");
   this.basePackages = basePackages;
}

在scan方法中会将方法参数赋值给成员变量basePackages。

最后在AnnotationConfigServletWebServerApplicationContext中还需要关注postProcessBean-Factory方法,该方法用于扫描包或者读取注解类,具体处理代码如下:

    protected void postProcessBeanFactory(ConfigurableListableBeanFactory
beanFactory) {
        super.postProcessBeanFactory(beanFactory);
        if (this.basePackages != null && this.basePackages.length > 0) {
           this.scanner.scan(this.basePackages);
        }
        if (!this.annotatedClasses.isEmpty()) {
           this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
        }
    }

在上述代码中主要是通过成员变量scanner和成员变量reader进行扫描或者读取操作将Bean定义进行加载的。

接下来需要对postProcessBeanFactory方法的执行时机进行说明,在SpringApplication中refresh方法涉及刷新操作,具体代码如下:

@Deprecated
protected void refresh(ApplicationContext applicationContext) {
   Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext);
   refresh((ConfigurableApplicationContext) applicationContext);
}

在这段代码中会传入参数应用上下文,本节分析的对象是AnnotationConfigServletWebServerApplicationContext,它是应用上下文的一个实现类,因此在这里有可能会是AnnotationConfigServletWebServerApplicationContext类型。

继续深入分析refresh方法可以发现它调用了应用上下文的刷新方法,最终的调用链路如下:

(1)org.springframework.boot.SpringApplication#run(java.lang.String...)。

(2)org.springframework.boot.SpringApplication#refreshContext。

(3)org.springframework.boot.SpringApplication#refresh(org.springframework.context.ApplicationContext)。

(4)org.springframework.boot.SpringApplication#refresh(org.springframework.context.ConfigurableApplicationContext)。

(5)org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#refresh。

(6)org.springframework.context.support.AbstractApplicationContext#refresh。

(7)org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext#postProcessBeanFactory。

第(5)步相当于是一个整体的refresh的入口,在第(6)步中会进一步调用postProcess-BeanFactory方法,此时就会对Spring Boot中的Bean定义进行初始化。需要注意的是,在普通启动时成员变量basePackages为null,成员变量annotatedClasses为空,此时不会有实际的加载操作。

接下来将对ServletWebServerApplicationContext进行分析,下面关注ServletWebServerApplicationContext成员变量,详细内容见表3-3。

表3-3 ServletWebServerApplicationContext成员变量

在了解成员变量后,下面对postProcessBeanFactory方法进行分析,它用于进行后置处理Bean工厂,在该类中具体处理代码如下:

    protected void postProcessBeanFactory(ConfigurableListableBeanFactory
beanFactory) {
         // 添加Bean后置处理器
          beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwar
eProcessor(this));
         // 添加忽略的依赖接口
         beanFactory.ignoreDependencyInterface(ServletContextAware.class);
         // 注册应用作用域
         registerWebApplicationScopes();
    }

在postProcessBeanFactory方法中主要的处理流程如下。

(1)添加Bean后置处理器,具体类型是WebApplicationContextServletContextAwareProcessor。

(2)添加需要忽略的依赖接口,具体接口是ServletContextAware。

(3)注册应用作用域。

在第(1)步中涉及的Bean后置处理器类型是WebApplicationContextServletContextAware-Processor,关于它的代码具体如下:

WebApplicationContextServletContextAwareProcessor中主要用于获取Servlet上下文和Servlet配置对象,这两个对象的获取主要和ServletContextAware有关,具体细节需要涉及Spring MVC相关内容,下面是具体的处理代码:

    public class ServletContextAwareProcessor implements BeanPostProcessor {
                 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;
         }
    }

在上述代码中可以发现,servletContext和servletConfig被设置给ServletConfigAware(类型是ServletConfigAware的Bean实例)。回到ServletWebServerApplicationContext的postProcess-BeanFactory方法中,最后会进行应用作用域注册,具体处理代码如下:

private void registerWebApplicationScopes() {
   ExistingWebApplicationScopes existingScopes = new
ExistingWebApplicationScopes(getBeanFactory());
   WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory());
   existingScopes.restore();
}

在上述代码中会通过ExistingWebApplicationScopes对象提供的restore方法来完成注册操作。接下来对refresh方法进行分析,具体处理代码如下:

public final void refresh() throws BeansException, IllegalStateException {
   try {
      super.refresh();
   }
   catch (RuntimeException ex) {
      WebServer webServer = this.webServer;
      if (webServer != null) {
          webServer.stop();
      }
      throw ex;
   }
}

在refresh方法中主要关注异常的处理,当出现异常时,会将成员变量webServer进行关闭。接下来对onRefresh方法进行分析,具体处理代码如下:

protected void onRefresh() {
   super.onRefresh();
   try {
      createWebServer();
   }
   catch (Throwable ex) {
      throw new ApplicationContextException("Unable to start web server", ex);
   }
}

在这段代码中主要是createWebServer方法的执行,详细代码如下:

在createWebServer方法中主要的处理流程如下:

(1)获取Web服务接口。

(2)获取Servlet上下文。

(3)如果Web服务和Servlet上下文为空则会进行如下操作:

①创建步骤标记器,将标记设置为创建阶段;

②获取servletWeb服务工厂;

③标记工厂数据;

④通过servletWeb服务工厂创建(获取)Web服务对象;

⑤标记结束状态;

⑥向Bean工厂注册单例对象。

(4)如果Servlet上下文不为空则通过ServletContextInitializer进行初始化。

(5)初始化属性源。

在上述处理流程中关于Web服务工厂的获取主要依赖于Bean名称和类型,具体处理代码如下:

protected ServletWebServerFactory getWebServerFactory() {
   String[] beanNames =
getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
   if (beanNames.length == 0) {
      throw new ApplicationContextException("Unable to start
ServletWebServerApplicationContext due to missing "
             + "ServletWebServerFactory bean.");
   }
   if (beanNames.length > 1) {
      throw new ApplicationContextException("Unable to start
ServletWebServerApplicationContext due to multiple "
             + "ServletWebServerFactory beans :" +
StringUtils.arrayToCommaDelimitedString(beanNames));
   }
   return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
}

在上述代码中主要处理流程是通过类型(ServletWebServerFactory)在容器中搜索所有的Bean名称,如果获取数量为0或者大于1就抛出异常,反之则取第一个元素作为Bean名称在容器中搜索并返回。 31hwrxLxPK9s9DmkoJpQF9TZGCD4+yZ5eX2AoGlgKsEYJrqIKEt1oP42l2hBt0Uz

点击中间区域
呼出菜单
上一章
目录
下一章
×