我们还是从大家最熟悉的DispatcherServlet 开始,我们最先想到的还是DispatcherServlet 的init()方法。我们发现在DispatherServlet 中并没有找到init()方法。但是经过探索,往上追索在其父类HttpServletBean 中找到了我们想要的init()方法,如下:

/*** Map config parameters onto bean properties of this servlet, and* invoke subclass initialization.* @throws ServletException if bean properties are invalid (or required* properties are missing), or if subclass initialization fails.*/
@Override
public final void init() throws ServletException {if (logger.isDebugEnabled()) {logger.debug("Initializing servlet '" + getServletName() + "'");}// Set bean properties from init parameters.PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);if (!pvs.isEmpty()) {try {//定位资源BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);//加载配置信息ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));initBeanWrapper(bw);bw.setPropertyValues(pvs, true);}catch (BeansException ex) {if (logger.isErrorEnabled()) {logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);}throw ex;}}// Let subclasses do whatever initialization they like.initServletBean();if (logger.isDebugEnabled()) {logger.debug("Servlet '" + getServletName() + "' configured successfully");}
}

在init()方法中,真正完成初始化容器动作的逻辑其实在initServletBean()方法中,我们继续跟进initServletBean()中的代码在FrameworkServlet 类中:

/*** Overridden method of {@link HttpServletBean}, invoked after any bean properties* have been set. Creates this servlet's WebApplicationContext.*/
@Override
protected final void initServletBean() throws ServletException {getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");if (this.logger.isInfoEnabled()) {this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");}long startTime = System.currentTimeMillis();try {this.webApplicationContext = initWebApplicationContext();initFrameworkServlet();}catch (ServletException ex) {this.logger.error("Context initialization failed", ex);throw ex;}catch (RuntimeException ex) {this.logger.error("Context initialization failed", ex);throw ex;}if (this.logger.isInfoEnabled()) {long elapsedTime = System.currentTimeMillis() - startTime;this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +elapsedTime + " ms");}
}

在上面的代码中终于看到了我们似曾相识的代码initWebAppplicationContext(),继续跟进:

/*** Initialize and publish the WebApplicationContext for this servlet.* <p>Delegates to {@link #createWebApplicationContext} for actual creation* of the context. Can be overridden in subclasses.* @return the WebApplicationContext instance* @see #FrameworkServlet(WebApplicationContext)* @see #setContextClass* @see #setContextConfigLocation*/
protected WebApplicationContext initWebApplicationContext() {//先从ServletContext中获得父容器WebAppliationContextWebApplicationContext rootContext =WebApplicationContextUtils.getWebApplicationContext(getServletContext());//声明子容器WebApplicationContext wac = null;//建立父、子容器之间的关联关系if (this.webApplicationContext != null) {// A context instance was injected at construction time -> use itwac = 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, etcif (cwac.getParent() == null) {// The context instance was injected without an explicit parent -> set// the root application context (if any; may be null) as the parentcwac.setParent(rootContext);}//这个方法里面调用了AbatractApplication的refresh()方法//模板方法,规定IOC初始化基本流程configureAndRefreshWebApplicationContext(cwac);}}}//先去ServletContext中查找Web容器的引用是否存在,并创建好默认的空IOC容器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 idwac = findWebApplicationContext();}//给上一步创建好的IOC容器赋值if (wac == null) {// No context instance is defined for this servlet -> create a local onewac = createWebApplicationContext(rootContext);}//触发onRefresh方法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;
}/*** Retrieve a {@code WebApplicationContext} from the {@code ServletContext}* attribute with the {@link #setContextAttribute configured name}. The* {@code WebApplicationContext} must have already been loaded and stored in the* {@code ServletContext} before this servlet gets initialized (or invoked).* <p>Subclasses may override this method to provide a different* {@code WebApplicationContext} retrieval strategy.* @return the WebApplicationContext for this servlet, or {@code null} if not found* @see #getContextAttribute()*/
@Nullable
protected WebApplicationContext findWebApplicationContext() {String attrName = getContextAttribute();if (attrName == null) {return null;}WebApplicationContext wac =WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName);if (wac == null) {throw new IllegalStateException("No WebApplicationContext found: initializer not registered?");}return wac;
}/*** Instantiate the WebApplicationContext for this servlet, either a default* {@link org.springframework.web.context.support.XmlWebApplicationContext}* or a {@link #setContextClass custom context class}, if set.* <p>This implementation expects custom contexts to implement the* {@link org.springframework.web.context.ConfigurableWebApplicationContext}* interface. Can be overridden in subclasses.* <p>Do not forget to register this servlet instance as application listener on the* created context (for triggering its {@link #onRefresh callback}, and to call* {@link org.springframework.context.ConfigurableApplicationContext#refresh()}* before returning the context instance.* @param parent the parent ApplicationContext to use, or {@code null} if none* @return the WebApplicationContext for this servlet* @see org.springframework.web.context.support.XmlWebApplicationContext*/
protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {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");}ConfigurableWebApplicationContext wac =(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);wac.setEnvironment(getEnvironment());wac.setParent(parent);String configLocation = getContextConfigLocation();if (configLocation != null) {wac.setConfigLocation(configLocation);}configureAndRefreshWebApplicationContext(wac);return wac;
}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 informationif (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 #refreshConfigurableEnvironment env = wac.getEnvironment();if (env instanceof ConfigurableWebEnvironment) {((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());}postProcessWebApplicationContext(wac);applyInitializers(wac);wac.refresh();
}

从上面的代码中可以看出,在configAndRefreshWebApplicationContext()方法中,调用refresh()方法,这个是真正启动IOC 容器的入口,后面会详细介绍。IOC 容器初始化以后,最后调用了DispatcherServlet 的onRefresh()方法,在onRefresh()方法中又是直接调用initStrategies()方法初始化SpringMVC 的九大组件:

/*** This implementation calls {@link #initStrategies}.*/
@Override
protected void onRefresh(ApplicationContext context) {initStrategies(context);
}/*** Initialize the strategy objects that this servlet uses.* <p>May be overridden in subclasses in order to initialize further strategy objects.*/
//初始化策略
protected void initStrategies(ApplicationContext context) {//多文件上传的组件initMultipartResolver(context);//初始化本地语言环境initLocaleResolver(context);//初始化模板处理器initThemeResolver(context);//handlerMappinginitHandlerMappings(context);//初始化参数适配器initHandlerAdapters(context);//初始化异常拦截器initHandlerExceptionResolvers(context);//初始化视图预处理器initRequestToViewNameTranslator(context);//初始化视图转换器initViewResolvers(context);//initFlashMapManager(context);
}

Web IOC 容器初体验相关推荐

  1. 从源码深处体验Spring核心技术--IOC容器初体验

    开局经验之谈:可能从这一篇文章开始,小伙伴们都会有点晕车的感觉了,但是这个系列并不是只是介绍下spring表面的一些肤浅的东西,本系列的目的是为了让大家从源码层次深入理解Spring,这也是大家在未来 ...

  2. Spring环境搭建,IoC容器初体验~

    由于最近的任务是关于IoC配置文件格式的转换,所以需要从Spring的IoC容器开始学起,今天根据网上的介绍搭建了Spring环境,并对其IoC容器进行了初体验.文章中涉及到的软件以及推荐的一本关于S ...

  3. Docker深入浅出系列 | 容器初体验

    Docker深入浅出系列 | 容器初体验 教程目标 Docker已经上市很多年,不是什么新鲜事物了,很多企业或者开发同学以前也不多不少有所接触,但是有实操经验的人不多,本系列教程主要偏重实战,尽量讲干 ...

  4. A-Frame WEB VR框架初体验

    aFrame是一个Web VR框架,底层是基于threejs的,刚好项目也用到了threejs,就用aFrame试了下效果.在网页上看起来,aFrame就是把threejs的的实现包装成一个实体标签. ...

  5. GWT(Google Web Toolkit)初体验

    为什么选择GWT? 众所周知,即使对于Ajax技术非常熟悉的开发者而言,Ajax应用的开发和调试过程也不是一件容易的事情,更困难的是,到目前为止,一直没有出现合适的开发工具能够支持Ajax应用的开发和 ...

  6. SaltStack WEB UI Halite初体验

    闲来无聊,话说saltstack webui halite还一直没玩,于是就凑今天体验一把: 很多尝鲜的同学都说halite的功能较少,而其也正符合其说明console,不过其UI我还是蛮喜欢的,个人 ...

  7. 从源码深处体验Spring核心技术--基于Xml的IOC容器的初始化

    IOC 容器的初始化包括 BeanDefinition 的 Resource 定位.加载和注册这三个基本的过程. 我们以ApplicationContext 为例讲解,ApplicationConte ...

  8. ASP.NET Core Web 应用程序系列(一)- 使用ASP.NET Core内置的IoC容器DI进行批量依赖注入(MVC当中应用)...

    在正式进入主题之前我们来看下几个概念: 一.依赖倒置 依赖倒置是编程五大原则之一,即: 1.上层模块不应该依赖于下层模块,它们共同依赖于一个抽象. 2.抽象不能依赖于具体,具体依赖于抽象. 其中上层就 ...

  9. spring之:XmlWebApplicationContext作为Spring Web应用的IoC容器,实例化和加载Bean的过程...

    它既是 DispatcherServlet 的 (WebApplicationContext)默认策略,又是 ContextLoaderListener 创建 root WebApplicationC ...

最新文章

  1. TestNG:org.openqa.selenium.os.UnixProcess$SeleniumWatchDog错误
  2. Angular cli 发布自定义组件
  3. mongoDB条件操作符
  4. php篮球比赛,篮球数据API接口 - 【篮球比赛动画直播变化数据】API调用示例代码...
  5. sap 一代增强_在SAP标准实施中不起眼的“小”功能,居然融了3个亿
  6. 数据库实践丨MySQL多表join分析
  7. HTML怎么在li中加select标签,Vue.js做select下拉列表的实例(ul-li标签仿select标签)_莺语_前端开发者...
  8. c 语言 字符 查找,C 语言实例 - 查找字符在字符串中出现的次数
  9. vue 中引入使用jquery
  10. 一个APP从启动到主页面显示经历了哪些过程?跳槽薪资翻倍
  11. BTA分论坛现场直击 | 区块链行业应用有待落地,游戏上链冰火两重天
  12. 30天自制操作系统第10天harib07d
  13. 快速编程的捷径——计算机达人成长之路(40)
  14. ChatGpt替代医生可能性分析
  15. TTS数据制作过程分享
  16. 在同一台机运行多个mysql 服务 多个主/从在同一主机_在同一台机运行多个Mysql 服务 多个主/从在同一主机...
  17. 【5G核心网】 5GC核心网之网元PCF
  18. CSP 202206-1 归一化处理
  19. linux驱动模块加载错误(insmod: can‘t insert ‘xxx.ko‘: invalid module format)的原因之一:内核或者配置不一致
  20. 微信企业号开发—通讯录

热门文章

  1. build.xml编译报错Specified VM install not found: type Standard VM, name jdk1.7.0_45
  2. 【转】【centos】启动网卡报错(Failed to start LSB: Bring up/down networking )解决办法总结...
  3. Oracle把逗号分割的字符串转换为可放入in的条件语句的字符数列
  4. myeclipse 重新关联项目和svn
  5. .cpp 编译成.a或是 .so
  6. phpcms避免字段值重复
  7. java解析json转Map
  8. JavaScript 发布-订阅模式
  9. 轻松为Windows系统快速配置多个网关
  10. idea autoscroll from source