一次request看spring的细节处理
spring获取处理一次请求的类的方式有两种
1.从配置文件spring-configs.xml中获取
2.从注解中获取
1.1从spring-configs.xml配置来看:
客户端:请求资源URL,web.xml中<servlet-mapping>标签<url-pattern>匹配请求资源
如果匹配到就调用对应的<servlet-name>中对应的servlet 通过<servlet-class>创建servlet对象dispatcherservlet
执行初始化方法通过set方法注入初始化属性值
classpath:spring-configs.xml,通过读取这个配置文件,创建出由spring管理的bean对象handlermapping处理映射,通过property标签实现set注入mapping的值,并将处理的结果以map集合的形式返还给dispatcherservlet,map集合中key为请求URL中/请求资源的名字,value对应业务层自己实现的controller对象,与要创建此对象的bean标签中id或name的属性值对应。dispatcherservlet将请求的URL交给业务层处理
问题:不同对象间获取request域中携带的参数是转发还是包含?
controller对象处理过后返回modelandview对象,交给viewresolver解析,视图解析器做的工作是从mv对象解析出要响应的资源,前缀+名字+后缀组成响应资源的地址,最终呈现给客户端,一次请求结束。
思考:在这一次请求中,request只创建一次且一直在整个请求链中存在并共享数据,直到一次请求结束才销毁request和response对象。
.do是个请求,这个站点在web.xml配置文件中配置了.do的请求都转发给一个servlet来处理,不是个文件,系统遇到这个.do的请求
后就会提交给某个servlet来处理,这个servlet会根据具体的配置转发给某个后台的程序进行数据处理,然后给数据传递到页面,最终给页面展现在
用户面前,不一定是struts的,这个请求是可以自己随便配置的,你可以配置成.html,这样就是经常看到假静态
2.1从注解模式理解spring框架:
@concroller是在告诉spring当前类为业务处理类
@service请求服务
@respontiry持久层
@compoent组件类
---------------------------------------------------------------------
以下内容摘抄自JAVA API中的源代码:
今天来探索SpringMVC一次请求过程的源码,首先需要找到程序运行的类及主要方法:
我们使用StringMVC首先需要在web.xml中设置一个前端控制器来处理请求,这个前端控制器是:org.springframework.web.servlet.DispatcherServlet
那么我们程序运行的入口就在这里。
从这里可以看出前端控制器是一个Servlet,我们寻找他的service方法,在DispatherServlet中并没有找到service方法,在其父类FrameworkServlet中找到service方法。如下:
FrameworkServlet:
- @Override
- protected void service(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String method = request.getMethod();
- if (method.equalsIgnoreCase(RequestMethod.PATCH.name())) {
- // 处理请求
- processRequest(request, response);
- }
- else {
- super.service(request, response);
- }
- }
- protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- long startTime = System.currentTimeMillis();
- Throwable failureCause = null;
- LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
- LocaleContext localeContext = buildLocaleContext(request);
- RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
- ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
- WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
- asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
- initContextHolders(request, localeContext, requestAttributes);
- try {
- // 调用doService方法处理请求
- doService(request, response);
- }
- ...
- @Override
- protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
- ...
- try {
- // 调用doDispatch方法处理请求
- doDispatch(request, response);
- }
- ...
- 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 {
- processedRequest = checkMultipart(request);
- multipartRequestParsed = processedRequest != request;
- // Determine handler for the current request.
- // 通过processedRequest,决定使用哪个handler来处理请求
- mappedHandler = getHandler(processedRequest);
- if (mappedHandler == null || mappedHandler.getHandler() == null) {
- 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.
- String method = request.getMethod();
- boolean isGet = "GET".equals(method);
- if (isGet || "HEAD".equals(method)) {
- long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
- if (logger.isDebugEnabled()) {
- String requestUri = urlPathHelper.getRequestUri(request);
- logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
- }
- if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
- return;
- }
- }
- // 执行预处理方法
- if (!mappedHandler.applyPreHandle(processedRequest, response)) {
- return;
- }
- try {
- // Actually invoke the handler.
- // 使用适配器执行目标方法,返回ModleAndView
- 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);
- }
- }
- }
到这里我们可以看出这个前端控制器主要工作是在 DispatherServlet的 doDispatch方法中完成。
大致流程如下:
通过processedRequest,决定使用哪个handler来处理请求
- HandlerExecutionChain mappedHandler = null;
- // Determine handler for the current request.
- mappedHandler = getHandler(processedRequest);
决定使用那个适配器处理请求(适配器模式)
- // Determine handler adapter for the current request.
- HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
执行预处理方法
- if (!mappedHandler.applyPreHandle(processedRequest, response)) {
- return;
- }
使用适配器执行目标方法,返回ModleAndView
- // Actually invoke the handler.
- mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
- mappedHandler.applyPostHandle(processedRequest, response, mv);
处理业务逻辑执行以后的返回结果,即处理视图,
调用本类的processDispatchResult方法
- private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
- HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
- ...
- // Did the handler return a view to render?
- if (mv != null && !mv.wasCleared()) {
- render(mv, request, response);//渲染视图
- if (errorView) {
- WebUtils.clearErrorRequestAttributes(request);
- }
- }
- ..
调用本类的render(mv, request, response);渲染视图。是将方法的返回值,最终变为一个View对象。
这个View对象正是我们在xml中配置的InternalResourceView
- protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
- ..
- // Determine locale for request and apply it to the response.
- Locale locale = this.localeResolver.resolveLocale(request);
- response.setLocale(locale);
- // View对象
- View view;
- if (mv.isReference()) {
- // We need to resolve the view name.
- view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
- if (view == null) {
- throw new ServletException(
- "Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" +
- getServletName() + "'");
- }
- }
- else {
- // No need to lookup: the ModelAndView object contains the actual View object.
- // 获得真正的view对象
- view = mv.getView();
- if (view == null) {
- throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
- "View object in servlet with name '" + getServletName() + "'");
- }
- }
- // Delegate to the View object for rendering.
- if (logger.isDebugEnabled()) {
- logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
- }
- try {
- // 内部视图解析器继续解析视图:
- view.render(mv.getModelInternal(), request, response);
- }
- catch (Exception ex) {
- if (logger.isDebugEnabled()) {
- logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '"
- + getServletName() + "'", ex);
- }
- throw ex;
- }
- }
调用 AbstractView类中的render方法
- @Override
- public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
- if (logger.isTraceEnabled()) {
- logger.trace("Rendering view with name '" + this.beanName + "' with model " + model +
- " and static attributes " + this.staticAttributes);
- }
- Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
- prepareResponse(request, response);
- // 渲染模型
- renderMergedOutputModel(mergedModel, request, response);
- }
调用 InternalResourceView类中的renderMergedOutputModel方法进行渲染模型、转发操作:
- //拿到转发器,进行转发
- @Override
- protected void renderMergedOutputModel(
- Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
- // Determine which request handle to expose to the RequestDispatcher.
- HttpServletRequest requestToExpose = getRequestToExpose(request);
- // Expose the model object as request attributes.
- exposeModelAsRequestAttributes(model, requestToExpose);
- // Expose helpers as request attributes, if any.
- exposeHelpers(requestToExpose);
- // Determine the path for the request dispatcher.
- String dispatcherPath = prepareForRendering(requestToExpose, response);
- //获得转发器
- // Obtain a RequestDispatcher for the target resource (typically a JSP).
- RequestDispatcher rd = getRequestDispatcher(requestToExpose, dispatcherPath);
- if (rd == null) {
- throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
- "]: Check that the corresponding file exists within your web application archive!");
- }
- // If already included or response already committed, perform include, else forward.
- if (useInclude(requestToExpose, response)) {
- response.setContentType(getContentType());
- if (logger.isDebugEnabled()) {
- logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
- }
- rd.include(requestToExpose, response);
- }
- else {
- // Note: The forwarded resource is supposed to determine the content type itself.
- if (logger.isDebugEnabled()) {
- logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
- }
- //进行转发
- rd.forward(requestToExpose, response);
- }
以下内容摘抄自want_water_fish的博客 :
一个请求在spring中的流程 (参与处理的类及主要方法)
DispatcherServlet.doDispatch (请求第一次处理、所有的请求都会执行这个方法。在这个方法中请求会被解析、分发。)-->
WebAsyncUtils.getAsyncManager (request中创建一个属性WebAsyncManager)-->
DispatcherServlet.checkMultipart (request是否是多文件类的请求)-->
DispatcherServlet.getHandler (获得当前requst的处理handler–spring提供了两个RequestMappingHandlerMapping、BeanNameUrlHandlerMapping)-->
AbstractHandlerMapping.getHandler (获得当前requst的处理handler)-->
AbstractHandlerMapping.getHandlerExecutionChain-->
UrlPathHelper.getLookupPathForRequest-->
DispatcherServlet.getHandlerAdapter (获得当前requst的处理handlerAdapter–spring提供了两个RequestMappingHandlerAdapter、HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter)-->
HandlerExecutionChain.applyPreHandle (处理拦截器)-->
AbstractHandlerMethodAdapter.handle (开始处理该请求)-->
RequestMappingHandlerAdapter.handleInternal (跳转至方法)-->
WebContentGenerator.checkRequest (检查方法是否支持、是否有session)-->
RequestMappingHandlerAdapter.invokeHandlerMethod (准备调用具体的执行方法)-->
RequestMappingHandlerAdapter.getDataBinderFactory (获得DataBinderFactory)-->
RequestMappingHandlerAdapter.createDataBinderFactory (创建DataBinderFactory)-->
RequestMappingHandlerAdapter.getModelFactory (获得ModelFactory)-->
ModelFactory.ModelFactory (创建ModelFactory)-->
RequestMappingHandlerAdapter.createInvocableHandlerMethod (创建ServletInvocableHandlerMethod)-->
ModelFactory.initModel (按照参数、初始化ModelFactory)-->
ModelFactory.invokeModelAttributeMethods (调用@ModelAttribute修饰的方法)-->
InvocableHandlerMethod.invokeForRequest (具体的调用执行方法)-->
InvocableHandlerMethod.getMethodArgumentValues (获取方法参数值)-->
HandlerMethodArgumentResolverComposite.resolveArgument (获得参数)-->
RequestResponseBodyMethodProcessor.resolveArgument (获得参数)-->
RequestResponseBodyMethodProcessor.readWithMessageConverters (将request中的参数转化成对象)-->
AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters (将request中的参数转化成对象)-->
AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters (将request中的参数转化成json对象、该系统用的是json数据传输)-->
ServletInvocableHandlerMethod.invokeAndHandle (调用真正的方法)-->
InvocableHandlerMethod.invokeForRequest (执行)-->
InvocableHandlerMethod.doInvoke (执行)-->
-->
自己controller中的方法
-->
InvocableHandlerMethod.doInvoke (执行返回)-->
InvocableHandlerMethod.invokeForRequest (执行返回)-->
ServletInvocableHandlerMethod.invokeAndHandle (执行返回)-->
HandlerMethodReturnValueHandlerComposite.handleReturnValue (处理方法返回的参数)-->
RequestResponseBodyMethodProcessor.handleReturnValue (处理方法返回的参数)-->
AbstractMessageConverterMethodProcessor.writeWithMessageConverters (处理方法返回的参数)-->
RequestMappingHandlerAdapter.invokeHandlerMethod (执行返回)-->
RequestMappingHandlerAdapter.getModelAndView (获得ModelAndView)-->
RequestMappingHandlerAdapter.handleInternal (执行返回)-->
AbstractHandlerMethodAdapter.handle (执行返回)-->
DispatcherServlet.doDispatch (执行返回)-->