web服务器请求响应全过程

时间:2022-11-24 19:11:36

今天我们来理一下web服务器请求和响应的整个完整过程。先来放两张图。

web服务器请求响应全过程web服务器请求响应全过程

首先浏览器发送请求,请求到达web服务器(比如apache服务器),然后到达servlet容器(比如tomcat),然后就到springmvc的DispatcherServlet,当然此时数据的表现形式已经早就不是url了,是对象了(万物皆对象,java的金句)。然后就开始springmvc的表演了,第一步DispatcherServlet调用映射处理器handleMapping,通过url找到对应的controller类,HandlerMapping接口的实现(只举了我认识的几个) : 


  • BeanNameUrlHandlerMapping :通过对比url和bean的name找到对应的对象 
    SimpleUrlHandlerMapping :也是直接配置url和对应bean,比BeanNameUrlHandlerMapping功能更多 
    DefaultAnnotationHandlerMapping : 主要是针对注解配置@RequestMapping的,已过时 
    RequestMappingHandlerMapping :取代了上面一个 

第二步DispatcherServlet调用HandlerAdapter来执行业务的方法,传一个handler返回一个modelandview。

在编写handler时要使用@Controller标识 它是一个控制器

如下:

@Controller
public class ItemsController3 {

}

类结构如下:

web服务器请求响应全过程

1、SimpleServletHandlerAdapter实际就是执行HttpServlet的service方法 springMVC源码分析--SimpleServletHandlerAdapter(二)

2、SimpleControllerHandlerAdapter实际就是执行Controller的handleRequest方法  springMVC源码分析--SimpleControllerHandlerAdapter(三)

3、HttpRequestHandlerAdapter实际就是执行HttpRequestHandler的handleRequest方法 springMVC源码分析--HttpRequestHandlerAdapter(四)

4、RequestMappingHandlerAdapter实际就是执行@RequestMapping注解的方法。

5、AnnotationMethodHandlerAdapter已结被废弃,就不做过多介绍

HandlerAdapter的接口中定义了三个方法:

(1)boolean supports(Object handler); 判断是否支持传入的Handler

(2)ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)  用来使用Handler处理请求

(3)long getLastModified(HttpServletRequest request, Object handler); 用来获取资料的Last-Modified值。

接口源码如下:

[java]  view plain  copy  print ?
  1. public interface HandlerAdapter {  
  2.   
  3.     boolean supports(Object handler);  
  4.   
  5.     ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;  
  6.   
  7.     long getLastModified(HttpServletRequest request, Object handler);  
  8.   
  9. }  

HandlerAdapter的执行操作,其执行过程在DispatcherServlet的doDispatch中,执行流程如下:

[java]  view plain  copy  print ?
  1. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {  
  2.           
  3.         ........  
  4.   
  5.         try {  
  6.               
  7.             try {  
  8.                   
  9.                 //获取合适的HandlerAdapter实现类  
  10.                 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());  
  11.                   
  12.             ........  
  13.                   
  14.                 if (isGet || "HEAD".equals(method)) {  
  15.                     long lastModified = ha.getLastModified(request, mappedHandler.getHandler());  
  16.                       
  17.                 }  
  18.             ........  
  19.                 //执行真正的请求操作  
  20.                 mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  
  21.   
  22.         ........  
  23.     }  
getHandlerAdapter的操作就是选择合适的HandlerAdapter来执行,设计模式中的适配器模式,handlerAdapters中的内容就是所有的HandlerAdapter的实现类。

[java]  view plain  copy  print ?
  1. protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {  
  2.         for (HandlerAdapter ha : this.handlerAdapters) {  
  3.             if (logger.isTraceEnabled()) {  
  4.                 logger.trace("Testing handler adapter [" + ha + "]");  
  5.             }  
  6.             if (ha.supports(handler)) {  
  7.                 return ha;  
  8.             }  
  9.         }  
  10.         throw new ServletException("No adapter for handler [" + handler +  
  11.                 "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");  
  12.     }  

这样就完成了Handler的真正调用过程,最终调用过程是返回一个ModelAndView对象。


然后就到了视图解析器了,在项目中用到了Velocity。首先需要配置Velocity,在wepapp-servlet.xml中是这样的

<bean id="velocityConfigurer"
class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
<property name="resourceLoaderPath" value="/WEB-INF/velocity/" />
<property name="configLocation" value="/WEB-INF/velocity.properties" />
<property name="velocityProperties">
<props>
<prop key="input.encoding">utf-8</prop>
<prop key="output.encoding">utf-8</prop>
<prop key="velocimacro.library">velocity-macro.vm</prop>
</props>
</property>
</bean>

<!-- 配置VelocityConfigurer,负责在spring中设置Velocity引擎。通过属性resourceLoaderPath告诉Velocity到哪里寻找它的模板。
   通常将模板放到WEB-INF下的某个子目录下,可以保证这些模板不能被直接访问。-->设置了属性文件的内容velocity.properties

当然在maven的依赖管理中也要加入Velocity的依赖。

web服务器请求响应全过程
<dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity</artifactId>
            <version>1.7</version>
</dependency>
<dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-tools</artifactId>
            <version>2.0</version>
</dependency>
 
配置视图解析器
<bean id="velocityViewResolver"
		class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
		<property name="suffix">
			<value>.vm</value>
		</property>
		<property name="exposeSpringMacroHelpers" value="true" />
		<property name="contentType" value="text/html;charset=utf-8" />
		<property name="attributes">
			<props>
                <prop key="webServerUrl">${tkm.web.server.url}</prop>
				<prop key="staticServerUrl">${tkm.static.server.url}</prop>
				<prop key="photoServerUrl">${tkm.photo.server.url}</prop>
            </props>
		</property>
		<property name="toolboxConfigLocation" value="/WEB-INF/vm/toolbox.xml" />
	</bean>
 
 

在webapp-servlet.xml文件中,还可以看到<property name="toolboxConfigLocation" value="/WEB-INF/toolbox.xml"/>,在web-inf路径下,建一个toolbox.xml文件,如下:

web服务器请求响应全过程
<?xml version="1.0" encoding="UTF-8" ?>
<toolbox>
    <tool>
        <key>UrlUtil</key>
        <class>com.nali.common.util.UrlUtil</class>
        <scope>application</scope>
    </tool>
    <tool>
        <key>VersionUtil</key>
        <class>com.ximalaya.shop.api.domain.util.VersionUtil</class>
        <scope>application</scope>
    </tool>
</toolbox>
web服务器请求响应全过程

  这个配置文件可以让我们在vm中使用后台java类中定义的方法.

说了半天不知道视图解析器是干嘛用的。

视图解析器就找到对应的view的,然后把模型的数据渲染到视图中,然后把视图返回会浏览器。那么viewresolver是怎么找到对应的视图的呢,视图和模型数据是怎么对应上的呢?

我的理解是这样:

浏览器发送了请求,servlet根据url找到了controller的类,在controller类中有这么一行代码 return "/tkm/mobile_main";

按我的理解这就是一个string,是一个modelandview,是一个逻辑视图名称,然后我们的视图处理器viewresolver就需要拿着这个去找真正的物理视图,是怎么找的呢,在我看的项目中用的是velocity框架。这部分不深究了,后期再理。不了解的东西有点多。