SpringMVC的DispatcherServlet的默认策略
在使用SpringMVC的时候,我们知道需要HandlerMapping定义请求路径与处理器之间的映射,需要HandlerAdapter来调用处理器方法并返回一个ModelAndView对象,需要ViewResolver来解析视图。这些是SpringMVC中最基本的接口。通常我们都需要在SpringMVC的配置文件中定义好需要使用的HandlerMapping、HandlerAdapter和ViewResolver,基于注解的SpringMVC配置也是类似的。所以一般我们的SpringMVC配置文件会是如下这样:
<mvc:annotation-driven/>
<!-- 快速注册视图解析器 -->
<mvc:view-resolvers>
<mvc:jsp prefix="/WEB-INF/views/" suffix=".jsp"/>
</mvc:view-resolvers>
mvc命名空间是Spring提供的一个简化SpringMVC配置的命名空间,<mvc:annotation-driven/>
会自动在Spring的bean容器中注册HandlerMapping接口实现RequestMappingHandlerMapping类型的bean和HandlerAdapter接口实现类RequestMappingHandlerAdapter类型的bean。<mvc:view-resolvers/>
是用来快速定义ViewResolver实现的,其中<mvc:jsp/>
会自动定义一个InternalResourceViewResolver类型的ViewResolver。
针对这些比较基本接口,即使我们不定义它们的实现,SpringMVC内部也给了默认的定义,它管这些叫策略。SpringMVC把这些默认策略都定义在一个叫DispatcherServlet.properties
的文件中,它与DispatcherServlet在同一个包中。以下是笔者在使用的4.1.0版本中的DispatcherServlet.properties文件中的定义。
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\ org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\ org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\ org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\ org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
从上面的定义中我们可以看出来,在使用SpringMVC时,即使你不定义HandlerMapping,SpringMVC默认也会给你定义一个BeanNameUrlHandlerMapping和DefaultAnnotationHandlerMapping。HandlerAdapter和ViewResolver也是一样的。还有一些其它的默认策略也请参考DispatcherServlet.properties中。如果默认策略不能满足你的要求,那么我们可以在bean容器中定义我们自己对应的实现,这个时候就会应用我们自己的实现了。我们拿初始化HandlerMapping为例,来看一下DispatcherServlet的源码。
/** * Initialize the HandlerMappings used by this class. * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace, * we default to BeanNameUrlHandlerMapping. */ private void initHandlerMappings(ApplicationContext context) { this.handlerMappings = null; if (this.detectAllHandlerMappings) { // Find all HandlerMappings in the ApplicationContext, including ancestor contexts. Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values()); // We keep HandlerMappings in sorted order. OrderComparator.sort(this.handlerMappings); } } else { try { 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. } } // 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"); } } }
从源码中我们可以看到,SpringMVC先会从绑定的ApplicationContext中获取对应的HandlerMapping定义,如果没有取到就会调用getDefaultStrategies(context, HandlerMapping.class)
从默认策略中获取。它的代码如下所示。
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) { String key = strategyInterface.getName(); String value = defaultStrategies.getProperty(key); if (value != null) { String[] classNames = StringUtils.commaDelimitedListToStringArray(value); List<T> strategies = new ArrayList<T>(classNames.length); for (String className : classNames) { try { Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader()); Object strategy = createDefaultStrategy(context, clazz); strategies.add((T) strategy); } catch (ClassNotFoundException ex) { throw new BeanInitializationException( "Could not find DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]", ex); } catch (LinkageError err) { throw new BeanInitializationException( "Error loading DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]: problem with class file or dependent class", err); } } return strategies; } else { return new LinkedList<T>(); } }
其中的defaultStrategies就是对应的DispatcherServlet.properties
文件中的内容。
private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties"; private static final Properties defaultStrategies; static { // Load default strategy implementations from properties file. // This is currently strictly internal and not meant to be customized // by application developers. try { ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class); defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); } catch (IOException ex) { throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage()); } }
(注:本文是基于SpringMVC4.1.0所写)
相关推荐
SpringMVC 的控制器默认为单例模式,这意味着在多线程环境下可能存在线程安全问题。为避免这个问题,控制器内部不应包含可变状态,或者可以使用 ThreadLocal 变量来处理线程局部变量。 SpringMVC 与 Struts2 的主要...
4. **多种请求资源映射策略**:SpringMVC 提供了灵活的 URL 映射策略,使得开发者能够方便地定义 URL 与控制器之间的对应关系。 5. **可扩展性**:SpringMVC 设计时考虑了扩展性,允许开发者根据需求添加自定义的...
SpringMVC提供了多种映射策略,包括基于注解的映射和基于XML配置的映射。 6. **HandlerAdapter**: 由于不同的控制器可能有不同的处理方式,HandlerAdapter为DispatcherServlet提供了一种统一的方式来调用处理器。它...
SpringMVC支持丰富的请求资源映射策略,并且是易于扩展的。 SpringMVC工作原理的核心是DispatcherServlet,它充当前端控制器的角色。当客户端发送请求到DispatcherServlet时,它首先会查询handlerMapping找到处理...
- **多种请求资源映射策略**:SpringMVC提供了多种方式将请求映射到相应的处理方法。 - **可扩展性**:SpringMVC的架构设计使得扩展非常方便,适应不断变化的需求。 3. **SpringMVC的工作原理** - 客户端向...
然而,这种方式可能不够灵活,因为默认Servlet的配置和缓存策略可能无法满足特定应用的需求。 ### 2. 自定义静态资源路径 如果你想要自定义静态资源的路径,可以使用`<mvc:resources>`标签。例如,以下配置将映射`...
`basename`属性用于指定资源文件的基础名称,`useCodeAsDefaultMessage`属性决定当找不到消息键时,是否使用键本身作为默认消息。 5. **LocaleResolver**:Spring提供了多种`LocaleResolver`实现,如`...
开发者可以根据实际需求调整配置,如自定义更多的HandlerMapping策略、使用不同的视图技术(如Thymeleaf、Freemarker等)替换默认的JSP视图,以及集成Spring Security等安全框架增强应用的安全性。
对于初学者,Spring MVC提供了默认的DispatcherServlet配置,以简化开发者的配置工作。这部分会详细介绍默认配置的细节以及如何根据需要进行修改。 6. DispatcherServlet的处理流程 这部分将详细介绍...
- **请求映射策略**:支持多种映射策略,使开发者可以根据需求定制。 - **易扩展性**:SpringMvc 设计得易于扩展,方便添加新的功能。 3. **SpringMVC 工作原理**: - 客户端向 DispatcherServlet 发送请求。 -...
在SpringMVC的组件中,除了Controller和View通常需要开发者根据业务需求来实现外,其他组件如DispatcherServlet、HandlerMapping、HandlerAdapter和ViewResolver通常由Spring框架提供默认实现。这些组件可以通过扩展...
SpringMVC的控制器默认是单例模式。在多线程环境下,这可能导致线程安全问题。解决方案是避免在控制器中定义实例变量,确保业务逻辑不依赖于控制器的状态。 6. **SpringMVC与Struts2的区别** - 入口点不同:...
SpringMVC的核心组件包括DispatcherServlet、Controller、ViewResolver、Model和View等。DispatcherServlet作为入口,负责请求分发;Controller处理业务逻辑;ViewResolver解析视图;Model存储数据;View负责渲染...
- `init`方法内部调用了`initStrategies`方法,该方法初始化了SpringMVC的各种策略,包括视图解析器、处理器映射器、处理器适配器等。 - 这个过程中还会创建子容器,用于管理特定于Web层的Bean。 ##### 示例代码 ...
默认情况下,Spring MVC会使用InternalResourceViewResolver,可以通过配置改变视图解析策略。 5. **模型数据绑定** @ModelAttribute注解用于将请求参数与方法参数进行绑定,使得数据可以直接传递到控制器方法中。...
- 提供灵活的请求资源映射策略。 - 易于扩展和定制。 ##### 常用注解 - `@RequestMapping`: 用于映射URL到特定的类或方法。 - `@PathVariable`: 用于从URL中提取动态参数。 - `@RequestParam`: 用于从HTTP请求中...