Spring MVC是Spring的一个重要模块,在使用Spring MVC的时候,需要在web.xml中配置DispatcherServlet,可以把它看成一个前端控制器的具体实现,还需要在Bean定义中配置Web请求和Controller(控制器)的对应关系,以及各种视图的展现方式。具体流程如下图所示。从中可以看出核心类是DispatcherServlet.
@Overridepublicfinalvoidinit()throws ServletException { if (logger.isDebugEnabled()) { logger.debug("Initializing servlet '" + getServletName() + "'"); } //获取Servlet的初始化参数,对Bean属性进行配置 // 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进行具体的初始化,在该类中它是有一个空方法,没有具体的实现。 //该处调用的是FrameworkServlet类的 initServletBean(); if (logger.isDebugEnabled()) { logger.debug("Servlet '" + getServletName() + "' configured successfully"); } }
//子类可以重写此项来执行自定义的初始化 //在调用此方法之前,将设置此servlet的所有bean属性。 /** * Subclasses may override this to perform custom initialization. * All bean properties of this servlet will have been set before this * method is invoked. * <p>This default implementation is empty. * @throws ServletException if subclass initialization fails */protectedvoidinitServletBean()throws ServletException { }
protected WebApplicationContext initWebApplicationContext(){ //首先通过ServletContext获得Spring容器,因为子容器SpringMvc要和父容器进行关联 WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); //定义Springmvc容器wac WebApplicationContext wac = null; //判断容器是否由编程式传入(即是否已经存在了容器实例),存在的话直接赋值给wac. 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) { //在ServletContext中寻找是否有SpringMVC容器,初次运行是没有的 // 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 //当war即没有被编程式注册到容器中,也没有在ServletContext找到,此时就要新建一个。 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. synchronized (this.onRefreshMonitor) { //到这里mvc的容器已经创建完毕,接着才是真正调用DispatcherServlet的初始化方法onRefresh onRefresh(wac); } }
if (this.publishContext) { // Publish the context as a servlet context attribute. //将SpringMVC容器存放到ServletContext中去,方便下次取出来。 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 + "]"); } }
privatevoidinitHandlerMappings(ApplicationContext context){ this.handlerMappings = null; if (this.detectAllHandlerMappings) { // Find all HandlerMappings in the ApplicationContext, including ancestor contexts. //这里导入所有的HandlerMapping Bean,这些Bean可以在当前的DispatcherServlet的IOC容器中,也可能在其双亲上下文 Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerMappings = new ArrayList<>(matchingBeans.values()); // We keep HandlerMappings in sorted order. AnnotationAwareOrderComparator.sort(this.handlerMappings); } } else { try { //可以根据名称从当前的IOC容器中通过getBean HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); this.handlerMappings = Collections.singletonList(hm); } catch (NoSuchBeanDefinitionException ex) { // Ignore, we'll add a default HandlerMapping later. } }
//如果没有找到handermappings,那么需要为Servlet设定默认的handerMappings,这些默认的值可以设置在DispatcherServlet.properties中 // Ensure we have at least one HandlerMapping, by registering // a default HandlerMapping if no other mappings are found. if (this.handlerMappings == null) { this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class); if (logger.isDebugEnabled()) { logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default"); } }