栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java > SpringBoot

DispatcherServlet请求流程解析-initWebApplicationContext(二)

SpringBoot 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

DispatcherServlet请求流程解析-initWebApplicationContext(二)

上面一篇文章提到,在Servlet初始化的时候,获取属性后调用initServletBean,这个方法会initWebApplicationContext,这是DispatcherServlet对后面的处理做了很多的预先准备工作,我们一起来看看它到底做了什么事情。

流程
  1. 先上代码,初始化和发布WebApplicationContext到servlet中,对于真正的创建操作是交给子类的createWebApplicationContext来实现的。

    protected WebApplicationContext initWebApplicationContext() {
// 获取WebApplicationContext,但是首次取得的值一般为null
 WebApplicationContext rootContext =  WebApplicationContextUtils.getWebApplicationContext(getServletContext());
 WebApplicationContext wac = null;

 if (this.webApplicationContext != null) {
     // A context instance was injected at construction time -> use it
     wac = this.webApplicationContext;
     if (wac instanceof ConfigurableWebApplicationContext) {
  ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
  if (!cwac.isActive()) {
      // The context has not yet been refreshed -> provide services such as
      // setting the parent context, setting the application context id, etc
      if (cwac.getParent() == null) {
   // The context instance was injected without an explicit parent -> set
   // the root application context (if any; may be null) as the parent
   cwac.setParent(rootContext);
      }
      configureAndRefreshWebApplicationContext(cwac);
  }
     }
 }
 if (wac == null) {
     // No context instance was injected at construction time -> see if one
     // has been registered in the servlet context. If one exists, it is assumed
     // that the parent context (if any) has already been set and that the
     // user has performed any initialization such as setting the context id
     wac = findWebApplicationContext();
 }
 if (wac == null) {
     // No context instance is defined for this servlet -> create a local one
     // 在当前的servlet中,没有对应的context实例时候,创建一个。
     wac = createWebApplicationContext(rootContext);
 }

 if (!this.refreshEventReceived) {
     // Either the context is not a ConfigurableApplicationContext with refresh
     // support or the context injected at construction time had already been
     // refreshed -> trigger initial onRefresh manually here.
     onRefresh(wac);
 }

 if (this.publishContext) {
     // Publish the context as a servlet context attribute.
     String attrName = getServletContextAttributeName();
     getServletContext().setAttribute(attrName, wac);
     if (this.logger.isDebugEnabled()) {
  this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
   "' as ServletContext attribute with name [" + attrName + "]");
     }
 }

 return wac;
    }
  • 首先获取WebApplicationContext,一般获取的值为null
  • 然后试着findWebApplicationContext(),这一步主要看其父类的是否已经注册了对应的context. 父类的context首次也为null
  • 如果WebApplicationContext还未找到,那么尝试创建一个WebApplicationContext

  1. 上一步对于最初的操作,获得的WebapplicationContext都是null的,因此需要创建一个WebapplicationContext.

    为当前的Servlet实例化WebApplicationContext


    protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {

//获取默认的getContextClass,默认的contextClass为XmlWebApplicationContext.class,可以从源码中看到
 Class contextClass = getContextClass();
 if (this.logger.isDebugEnabled()) {
     this.logger.debug("Servlet with name '" + getServletName() +
      "' will try to create custom WebApplicationContext context of class '" +
      contextClass.getName() + "'" + ", using parent context [" + parent + "]");
 }
 if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
     throw new ApplicationContextException(
      "Fatal initialization error in servlet with name '" + getServletName() +
      "': custom WebApplicationContext class [" + contextClass.getName() +
      "] is not of type ConfigurableWebApplicationContext");
 }

 // 使用BeanUtils实例化ApplicationContext类。
 ConfigurableWebApplicationContext wac =
  (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

 wac.setEnvironment(getEnvironment());
 wac.setParent(parent);
 wac.setConfigLocation(getContextConfigLocation());

 configureAndRefreshWebApplicationContext(wac);

 return wac;
    }
  • 首先获取默认的要实例化的ApplicationContxt类,默认的为XmlWebApplicationContext
  • 使用BeanUtil实例化ApplicationContxt的类,BeanUtils是个很有用的方法,可以多看下
  • ApplicationContxt被实例化之后,做一些配置,设置当前的Environment,设置父类(如果有的话),获取contextLocation的位置(web.xml中可以设置,当然也有默认值)
  • 配置然后刷新WebApplicationContex类
  1. 对WebApplicationContext类做配置和刷新。
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
 if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
     // The application context id is still set to its original default value
     // -> assign a more useful id based on available information
     if (this.contextId != null) {
  wac.setId(this.contextId);
     }
     else {
  // Generate default id...
  wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
   ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
     }
 }

 wac.setServletContext(getServletContext());
 wac.setServletConfig(getServletConfig());
 wac.setNamespace(getNamespace());
 wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

 // The wac environment's #initPropertySources will be called in any case when the context
 // is refreshed; do it eagerly here to ensure servlet property sources are in place for
 // use in any post-processing or initialization that occurs below prior to #refresh
 ConfigurableEnvironment env = wac.getEnvironment();
 if (env instanceof ConfigurableWebEnvironment) {
     ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
 }

 postProcessWebApplicationContext(wac);
 applyInitializers(wac);
 wac.refresh();
    }
  • 首先生成WebApplicationContext的id,用于后面加载Spring-MVC的配置文件
  • 在WebApplicationContext中设置容器的ServletContext,ServiletConfig,并设置默认的命名空间
  • 添加ApplicationContext的监听器,监听ContextRefresh事件
  • 初始化环境属性
  • postProcessWebApplicationContext,初始化WebApplicationContext之后做的事情,默认为空,后面自行扩展的时候可以覆盖
  • applyInitializers, 后面可以多了解下,初始器
  • 刷新WebApplicationContext.

  1. WebApplicationContext的刷新操作。
  • 使用synchronized保证线程安全
  • 下面每一个方法都包含一些具体的操作
@Override
    public void refresh() throws BeansException, IllegalStateException {
 synchronized (this.startupShutdownMonitor) {
     // Prepare this context for refreshing.
     // 准备刷新
     prepareRefresh();

     // Tell the subclass to refresh the internal bean factory.
     // 告诉子类刷新内部的bean factory
     ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

     // Prepare the bean factory for use in this context.
     // 准备beanfactory来使用
     prepareBeanFactory(beanFactory);

     try {
  // Allows post-processing of the bean factory in context subclasses.

  postProcessBeanFactory(beanFactory);

  // Invoke factory processors registered as beans in the context.
  invokeBeanFactoryPostProcessors(beanFactory);

  // Register bean processors that intercept bean creation.
  registerBeanPostProcessors(beanFactory);

  // Initialize message source for this context.
  initMessageSource();

  // Initialize event multicaster for this context.
  initApplicationEventMulticaster();

  // Initialize other special beans in specific context subclasses.
  onRefresh();

  // Check for listener beans and register them.
  registerListeners();

  // Instantiate all remaining (non-lazy-init) singletons.
  finishBeanFactoryInitialization(beanFactory);

  // Last step: publish corresponding event.
  finishRefresh();
     }

     catch (BeansException ex) {
  if (logger.isWarnEnabled()) {
      logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
  }

  // Destroy already created singletons to avoid dangling resources.
  destroyBeans();

  // Reset 'active' flag.
  cancelRefresh(ex);

  // Propagate exception to caller.
  throw ex;
     }

     finally {
  // Reset common introspection caches in Spring's core, since we
  // might not ever need metadata for singleton beans anymore...
  resetCommonCaches();
     }
 }
    }
  1. 仔细看一下refresh中的每一个大方法,首先prepareRefresh,可以看到prepareRefresh,确实只做一些准备性的工作,没有实质性的处理。
protected void prepareRefresh() {
 this.startupDate = System.currentTimeMillis();
 this.closed.set(false);
 this.active.set(true);

 if (logger.isInfoEnabled()) {
     logger.info("Refreshing " + this);
 }

 // Initialize any placeholder property sources in the context environment
 initPropertySources();

 // Validate that all properties marked as required are resolvable
 // see ConfigurablePropertyResolver#setRequiredProperties
 getEnvironment().validateRequiredProperties();

 // Allow for the collection of early ApplicationEvents,
 // to be published once the multicaster is available...
 this.earlyApplicationEvents = new linkedHashSet();
    }
  1. obtainFreshBeanFactory()告诉子类刷新内部的beanfactory, 默认的beanFactory是DefaultListableBeanFactory。

obtainFreshBeanFactory中刷新BeanFactory的操作是交给其子类来实现的。AbstractRefreshableApplicationContext是真正做了刷新的操作,并且加载了beanDefinitions.

关于如何loadBeandefenition,后面可以再深入去看



    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
 refreshBeanFactory();
 ConfigurableListableBeanFactory beanFactory = getBeanFactory();
 if (logger.isDebugEnabled()) {
     logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
 }
 return beanFactory;
    }


    @Override
    protected final void refreshBeanFactory() throws BeansException {
 if (hasBeanFactory()) {
     destroyBeans();
     closeBeanFactory();
 }
 try {
     DefaultListableBeanFactory beanFactory = createBeanFactory();
     beanFactory.setSerializationId(getId());
     customizeBeanFactory(beanFactory);

     //加载bean的定义
     loadBeanDefinitions(beanFactory);
     synchronized (this.beanFactoryMonitor) {
  this.beanFactory = beanFactory;
     }
 }
 catch (IOException ex) {
     throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
 }
    }
  1. 让beanFactory准备好使用context. 可以看到beanFactory做了很多的配置
  • 设置ClasLoader,SPEL,PropertyEditorRegistrar
  • 添加ApplicationContextAware,用于让bean设置ApplicationContextde .等等
  • 解析依赖关系ResolvableDependency相关的内容
  • 一些需要早期的bean处理
  • 注册一些系统默认的bean,如Environment,SystemProperties等等

    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
 // Tell the internal bean factory to use the context's class loader etc.
 beanFactory.setBeanClassLoader(getClassLoader());
 beanFactory.setBeanexpressionResolver(new StandardBeanexpressionResolver(beanFactory.getBeanClassLoader()));
 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

 // Configure the bean factory with context callbacks.
 beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
 beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
 beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
 beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
 beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
 beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
 beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

 // BeanFactory interface not registered as resolvable type in a plain factory.
 // MessageSource registered (and found for autowiring) as a bean.
 beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
 beanFactory.registerResolvableDependency(ResourceLoader.class, this);
 beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
 beanFactory.registerResolvableDependency(ApplicationContext.class, this);

 // Register early post-processor for detecting inner beans as ApplicationListeners.
 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

 // Detect a LoadTimeWeaver and prepare for weaving, if found.
 if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
     beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
     // Set a temporary ClassLoader for type matching.
     beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
 }

 // Register default environment beans.
 if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
     beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
 }
 if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
     beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
 }
 if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
     beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
 }
    }
  1. beanFactory处理之后的处理,这一步可以理解为上一步的后续处理,和上一步类似都是对beanFactory的处理

    @Override
    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
 beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
 beanFactory.ignoreDependencyInterface(ServletContextAware.class);
 beanFactory.ignoreDependencyInterface(ServletConfigAware.class);

 WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
 WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
    }
  1. 激发上下文中创建bean的后续操作,这个内部包含了很多内容,大部分的操作在PostProcessorRegistrationDelegate类里面的invokeBeanFactoryPostProcessors中,一个方法写了100多行,内容很多,这里就粘贴出来了,东西太多。记得PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors

包括下一步的registerBeanPostProcessors操作也是由PostProcessorRegistrationDelegate来完成的。这个类看来也挺重要,不过它的访问权限是默认的,看来Spring不想暴露出来给我们用。

PostProcessorRegistrationDelegate

  1. initMessageSource,操作,进入里面看到这些操作都是围绕着BeanFactory在进行,beanFactory设置DelegatingMessageSource。

  2. 设置Application广播发出器,可以看到内部仍然是对beanFactory设置一个默认的类

  3. onRefresh方法其实现类基本上都是在初始化主题,GenericWebApplicationContext与AbstractRefreshableWebApplicationContext都是如此

  4. 注册监听器,看截图可以看出其主要在上面的事件caster中添加应用事件的bean

  1. 看一下最后的操作吧,结束刷新操作,发布已经刷新后的事件。
    
    protected void finishRefresh() {
 // Initialize lifecycle processor for this context.
 initLifecycleProcessor();

 // Propagate refresh to lifecycle processor first.
 getLifecycleProcessor().onRefresh();

 // Publish the final event.
 publishEvent(new ContextRefreshedEvent(this));

 // Participate in LiveBeansView MBean, if active.
 LiveBeansView.registerApplicationContext(this);
    }
  1. 重置Spring中的cache
    
    protected void resetCommonCaches() {
 ReflectionUtils.clearCache();
 ResolvableType.clearCache();
 CachedIntrospectionResults.clearClassLoader(getClassLoader());
    }
回顾

感觉Spring-mvc中的initWebApplicationContext做了很多的事情,先抓住大方向,细节很多,回顾一下这次看到了那些内容。

从initServletBean开始,然后initWebApplicationContext,初始情况下ApplicationContext是为null的,我们需要创建默认的ApplicationContext,Spring-mvc中默认的ApplicationContext是XmlWebApplicationContext。

使用反射创建XmlWebApplicationContext之后,将XmlWebApplicationContext作为参数传递到配置和刷新XmlWebApplicationContext的方法中,接下来的操作,集中在对XmlWebApplicationContext的配置中。

配置Enviriment,ServletConfig,初始属性,命名空间,过滤器等等。最后调用XmlWebApplicationContext的refresh操作。

refresh操作中主要围绕bean相关的内容在操作,创建beanFactory,然后对beanFactory做配置,同时加载bean,bean的生命周期等等操作。然后注册bean以外的内容,配置主题,事件,消息等等,最后结束刷新,完成整个bean的生命周期。

最后

这里只是initWebApplicationContext,感觉bean的生命周期处理也是在这一步内部配置的,后面有关bean的生命周期,可以在内部仔细看一下。

initWebApplicationContext中,涉及到很多的类,很多默认的类,多读几遍,也许将来自己造轮子的某一天可以参考Spring的设计。

本人才疏学浅,阅读Spring源码的过程,做了一些记录,供参考作用,如果感兴趣,想后续交流欢迎一起探讨。

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号