核心架构的具体流程步骤如下:
1、 首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;
2、 DispatcherServlet——>HandlerMapping, HandlerMapping将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器)对象,通过这种策略模式,很容易添加新的映射策略;
3、 DispatcherServlet——>HandlerAdapter,HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;
4、 HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView对象(包含模型数据、逻辑视图名);
5、 ModelAndView的逻辑视图名——> ViewResolver, ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;
6、 View——>渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术;
7、返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。
用我的话来概括如下:
由HandlerMapping得到HandlerExecutionChain(其包含Object handler,interceptors),handler就是Controller实例,接着由handler得到HandlerAdapter(ha),最后由ha.handle(..)得到ModelAndView。注意,在执行目标方法之前,会升序调用interceptors,之后又会倒序调用interceptors。那么,HandlerAdapter是个什么东西呢,我在DispatcherServlet.properties里可以看到默认配了3种adapter,其实还有一种adapter没加进配置文件,如果你了解springmvc的发展史和解决mvc的思路,你就会明白为什么有多种实现方式了。最初springmvc采用的是实现Controller接口的方式,javase 1.5开始,springmvc采用了更方便的注解方式来标明Controller类,这两种方式对应的adapter分别是SimpleControllerHandlerAdapter和AnnotationMethodHandlerAdapter,所以我们可以重点关注AnnotationMethodHandlerAdapter。
下面来好好谈谈DispatcherServlet的部分代码
我们注意到该类中定义了一些well-known常量,呵呵,众所周知的常量
public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";
public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";
public static final String THEME_RESOLVER_BEAN_NAME = "themeResolver";
/**
* Well-known name for the HandlerMapping object in the bean factory for this namespace.
* Only used when "detectAllHandlerMappings" is turned off.
* @see #setDetectAllHandlerMappings
*/
public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";
public static final String HANDLER_ADAPTER_BEAN_NAME = "handlerAdapter";
public static final String HANDLER_EXCEPTION_RESOLVER_BEAN_NAME = "handlerExceptionResolver";
public static final String REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME = "viewNameTranslator";
public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver";
public static final String FLASH_MAP_MANAGER_BEAN_NAME = "flashMapManager";
private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
我们在配置文件中给相关组件bean命名时,可以保持和只写常量值一致,毕竟别人的命名是相当标准的,不过,这从逻辑上不是必须的,你甚至可以不声明bean的id,因为该类提供了如下变量
/** Detect all HandlerMappings or just expect "handlerMapping" bean? */
private boolean detectAllHandlerMappings = true;
/** Detect all HandlerAdapters or just expect "handlerAdapter" bean? */
private boolean detectAllHandlerAdapters = true;
/** Detect all HandlerExceptionResolvers or just expect "handlerExceptionResolver" bean? */
private boolean detectAllHandlerExceptionResolvers = true;
/** Detect all ViewResolvers or just expect "viewResolver" bean? */
private boolean detectAllViewResolvers = true;
/** Perform cleanup of request attributes after include request? */
private boolean cleanupAfterInclude = true;
/** MultipartResolver used by this servlet */
private MultipartResolver multipartResolver;
/** LocaleResolver used by this servlet */
private LocaleResolver localeResolver;
/** ThemeResolver used by this servlet */
private ThemeResolver themeResolver;
/** List of HandlerMappings used by this servlet */
private List<HandlerMapping> handlerMappings;
/** List of HandlerAdapters used by this servlet */
private List<HandlerAdapter> handlerAdapters;
/** List of HandlerExceptionResolvers used by this servlet */
private List<HandlerExceptionResolver> handlerExceptionResolvers;
/** RequestToViewNameTranslator used by this servlet */
private RequestToViewNameTranslator viewNameTranslator;
/** FlashMapManager used by this servlet */
private FlashMapManager flashMapManager;
/** List of ViewResolvers used by this servlet */
private List<ViewResolver> viewResolvers;
初始化方法中,执行了组件的初始化
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
我们拿出initHandlerMappings(context)来瞅瞅
/**
* 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");
}
}
}
通过该方法我们可以知道,当detectAllHandlerMappings为true时,直接到mvc容器及其父容器中寻找所有类型为HandlerMapping的bean,而detectAllHandlerMappings默认恰为true,因此我们完全可以不声明bean的id。当detectAllHandlerMappings为false时(可通过在web.xml里配置servlet参数来改变默认值),则在mvc容器寻找名为"handlerMapping"的bean。如以上两种情况都没找到bean,将会实例化DispatcherServlet.properties中配置的bean。
doService方法里有这么一段
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<String, Object>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
这是用于对页面有include的情况做的请求数据快照处理。
下面进入重点doDispatch方法
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// multipart包装处理,我们常用CommonsMultipartResolver
processedRequest = checkMultipart(request);
multipartRequestParsed = processedRequest != request;
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest, false);
if (mappedHandler == null || mappedHandler.getHandler() == null) { // 404
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler. // 代码省略
// 调用目标方法前,顺序执行拦截器
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
try {
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
applyDefaultViewName(request, mv);
// 调用目标方法后逆序执行拦截器
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
return;
}
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
HandlerExecutionChain
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (getInterceptors() != null) {
for (int i = 0; i < getInterceptors().length; i++) {
HandlerInterceptor interceptor = getInterceptors()[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
/**
* Apply postHandle methods of registered interceptors.
*/
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
if (getInterceptors() == null) {
return;
}
for (int i = getInterceptors().length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = getInterceptors()[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
/**
* Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
* Will just invoke afterCompletion for all interceptors whose preHandle invocation
* has successfully completed and returned true.
*/
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
throws Exception {
if (getInterceptors() == null) {
return;
}
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = getInterceptors()[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
HandlerInterceptor
public interface HandlerInterceptor {
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception;
void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception;
void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception;
}
自定义
public class ExceptionHandler implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
request.setAttribute("exception",ex.getMessage());
ModelAndView mav = new ModelAndView();
mav.setViewName("/error");
return mav;
}
}
相关推荐
综上所述,SpringMVC的学习路线涵盖了从基础到高级的多个方面,包括框架使用、代码实践、架构理解、组件整合、参数绑定、注解使用、异常处理、数据交互、Restful实现以及拦截器开发等多个知识点,为Java后台开发者...
本文将深入探讨 SpringMVC 的学习路线,包括基础配置、控制器定义、请求处理以及注解的使用。 首先,让我们从【标题】和【描述】中的内容开始。SpringMVC 学习笔记涵盖了从基础到高级的多个方面,如源码分析、实例...
接着,学习SpringMVC的生命周期和请求处理流程。再深入MyBatis,理解其映射文件和动态SQL的用法。最后,通过Maven管理项目,了解其生命周期和插件机制。实践中,可以创建一个简单的CRUD应用,逐步将SSM框架整合并...
SpringMVC是Spring框架的一个模块,专门用于处理Web层的请求。它通过DispatcherServlet接收HTTP请求,然后将请求分发给处理器(Controller),控制器再调用服务层方法完成业务逻辑,最后返回视图(View)给客户端。...
采用当前主流的B/S(Browser/Server)架构,即用户通过浏览器端进行操作,服务器端处理请求并返回数据,这种架构使得系统具有良好的跨平台性和易用性。JAVA编程语言作为后端开发语言,以其强类型、面向对象的特性,...
5. 物流路线规划:可能使用第三方API进行物流路线的优化计算。 6. 系统监控:通过Spring Actuator等工具监控系统的性能和健康状况。 这些技术的结合使得物流系统能够高效、可靠地处理大量数据,提供实时的货物追踪...
SpringMVC通过DispatcherServlet接收请求,Controller处理请求,Model存储数据,View负责渲染视图,整个流程清晰明了。 MyBatis是一个优秀的持久层框架,它简化了数据库操作,通过XML或注解的方式将SQL语句与Java...
在城市公共交通路线推荐系统中,SpringMVC处理用户请求,调用业务逻辑,并返回响应结果。 - **MyBatis**:是一个持久层框架,简化了数据库操作。它允许开发者直接编写SQL语句,通过XML或注解的方式将SQL与Java代码...
SpringMVC提供了处理HTTP请求、路由请求到相应的控制器、数据绑定、验证、视图解析等功能。在这个药品销售配送系统中,SpringMVC将处理用户请求,调用服务层进行业务处理,然后返回响应数据。 4. **目录结构** - ...
在这一阶段,你会学习如何处理HTTP请求,如何使用JSP进行视图层开发,以及如何通过Servlet进行业务逻辑处理。 Spring框架是JavaEE开发中的核心组件,它简化了依赖注入(Dependency Injection)和面向切面编程...
Spring负责依赖注入和事务管理,SpringMVC处理HTTP请求,MyBatis则作为持久层框架,用于与数据库交互。 5. **微信小程序**:可能表示该系统与微信小程序进行了集成,允许用户通过微信小程序访问和使用旅游服务,提升...
在系统中,SpringMVC处理HTTP请求,调用相应的控制器方法,然后将结果传递给视图层进行渲染。 **3. MyBatis框架** MyBatis是一个持久层框架,它简化了数据库操作,使得开发者可以直接编写SQL语句,避免了传统的JDBC...
首先,SSM是Java Web开发中常见的三层架构模式,由Spring框架负责依赖注入(DI)和面向切面编程(AOP),SpringMVC处理HTTP请求和响应,而MyBatis作为持久层框架,实现了数据库操作的简单化。在游乐园智慧向导系统中...
在Spring MVC中,控制器接收HTTP请求,处理业务逻辑,并决定如何展示结果。模型层负责业务对象的创建和管理,而视图层则负责数据的展示。 SSH框架组合则是经典的Java Web开发解决方案。Struts2作为MVC框架,处理...
Spring提供了全面的事务管理、依赖注入等功能,SpringMVC则负责处理HTTP请求和响应,而MyBatis作为持久层框架,简化了数据库操作。这个系统的实现,将充分展示SSM框架在实际项目中的应用。 1. **系统架构设计**:...
SSM是Java Web开发中的常用组合,Spring作为核心容器管理Bean,SpringMVC处理HTTP请求,MyBatis则负责数据库交互。在这个项目中,Spring通过依赖注入实现业务对象的管理和协作,SpringMVC负责接收和转发请求,...
Struts2是另一个常用的Java Web框架,它基于Model-View-Controller模式,提供了丰富的插件和拦截器机制,便于实现请求处理、页面跳转和异常管理。在物流管理系统中,Struts2可以处理HTTP请求,调用后台服务,然后将...
- 使用SpringMVC接收前端请求,处理业务逻辑,并返回相应的数据。 - MyBatis负责数据持久化操作,包括增删改查等基本操作。 3. **安全性**: - 对敏感信息(如密码)进行加密处理,保护用户隐私。 - 实现权限控制...
- **后端Controller**:SpringMVC的Controller负责处理前端的请求,调用Service层的方法,完成业务逻辑。 - **Service层**:包含业务逻辑,可能包括路径规划算法,如Dijkstra算法或A*算法,用于计算两点间的最短或...