本节将对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名称在容器中搜索并返回。