SpringMVC初始化

1. 入口: SpringServletContainerInitializer :

@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer

原理及过程

  • 根据Servlet3+的规定,Servlet容器将自动扫描并加载实现了ServletContainerInitializer接口的类,然后调用onStartup方法,并且会传入@HandlesTypes注解参数指定的类型(Class实例);
  • SpringMVC定义了WebApplicationInitializer接口,并在@HandlesTypes注解中声明,因此Servlet容器会扫描到所有WebApplicationInitializer类形,并在onStartup方法中传入该类集合及ServletContext;
  • onStartup方法中,过滤掉接口和抽象类后,调用该Class的newInstance方法生成实例,并放入集合;
  • 排序后,依次调用WebApplicationInitializer实例的onStartup方法,并传入ServletContext;
  • SpringMVC为WebApplicationInitializer提供了很多抽象实现类,用户使用时,只需继承其中之一即可,或者也可以自己从头实现,并在onStartup方法中完成DispatcherServlet的注册或自己的初始化动作等等;
  • AbstractAnnotationConfigDispatcherServletInitializer是其中比较常用且好用的一个,用户只需继承它,且实现三个抽象方法,提供根容器配置类集合、ServletConfig配置类集合、HTTP访问映射根路径;

2. 初始化器: WebApplicationInitializer

继承结构

AbstractAnnotationConfigDispatcherServletInitializer-> AbstractDispatcherServletInitializer-> AbstractContextLoaderInitializer---> WebApplicationInitializer

  • AbstractContextLoaderInitializer:
    • 直接实现WebApplicationInitializer,onStartup方法中只调用了registerContextLoaderListener,注册一个上下文监听器;
    • 创建一个根容器,WebApplicationContext的实例,创建方法是模板方法,具体由子类实现;
    • 创建一个监听器ContextLoaderListener实例,传入根容器;
      • 注:IOC根容器的真正初始化就在监听器中,contextInitialized->initWebApplicationContext->configureAndRefreshWebApplicationContext,最终会调用容器的refresh()方法完成初始化[见spring-web-4.3.3,源码ContextLoader类,444行,wac.refresh();]
    • listener.setContextInitializers什么都没干,因为getRootApplicationContextInitializers()返回null;
    • 将监听器添加到ServletContext中;
  • AbstractDispatcherServletInitializer
    • 重写onStartup方法,除调用父类onStartup方法外,添加一行调用:registerDispatcherServlet,用于注册DispatcherServlet;
    • 创建DispatcherServlet,返回类型为父类FrameworkServlet;
    • 创建注册器并设置映射路径(模板方法,由用户实现的子类提供)、立即加载、是否异步等,下面是代码;
    • 获取并注册Filter(截止4.3.3,getServletFilters()总是返回空);
    • 最后调用模板方法 customizeRegistration(ServletRegistration.Dynamic registration), 注:该方法并未实现;
    ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
    registration.setLoadOnStartup(1);
    registration.addMapping(getServletMappings());
    registration.setAsyncSupported(isAsyncSupported());
  • AbstractAnnotationConfigDispatcherServletInitializer
    实现的模板方法createRootApplicationContextcreateServletApplicationContext,用于创建IOC的根容器及WEB容器(子容器),并提供新的模板方法protected abstract Class<?>[] getRootConfigClasses();protected abstract Class<?>[] getServletConfigClasses();,让用户实现,以提供配置类和ServletConfig配置类
    • createRootApplicationContext: 通过模板方法getRootConfigClasses获取配置类,然后new一个AnnotationConfigWebApplicationContext实例,然后调用其register方法完成配置类的注册,最后返回该实例;
    • createServletApplicationContext: 直接new一个AnnotationConfigWebApplicationContext对象做为子容器,然后通过模板方法getServletConfigClasses()获取配置类数组,遍历数组,注册到子容器中等待初始化;
  • 最后,用户继承AbstractAnnotationConfigDispatcherServletInitializer,实现三个模板方法,提供配置类、http访问映射根路径等;

总结

springMVC的初始化有两条线:

  • ContextLoaderListener监听器,在其初始化方法中实现根容器的初始化;
  • DispatcherServlet中的init方法,最终实现子容器的初始化;

回想之前web.xml中配置spring及springmvc,先配置一个监听器,再配置一个Servlet,即springmvc的唯一实现DispatcherServlet; 注解+javaConfig的方式也是一样的,只不过借助于servlet3+的特性,省去了web.xml的配置,并在框架代码中实现的监听器及Servlet的注册,用户只需要提供配置类,在配置类中标注注解以及定义Bean即可完成之前由web.xml+spring.xml实现的配置,简化了开发,并且更方便扩展,比如可以编写读取远程配置的代码,并在配置类中提供调用方法,然后标注一个@Bean即可实现集中化、动态化的配置;

转载于:https://my.oschina.net/u/2407208/blog/1787749

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值