第一部分:网站基础知识
一、网站架构
1、软件类型
(1)三类:单机、CS和BS。
(2)网络传输:OSI七层参考模型和TCP/IP四层参考模型。
OSI七层模型 TCP/IP四层模型
应用层、表示层、会话层 应用层
传输层 传输层
网络层 网际互联层
数据链路层、物理层 网络接入层
2、海量数据解决方案
(1)缓存和页面静态化。
(2)数据库优化: 表结构优化、SQL语句优化、分区与分表、索引优化、使用存储过程。
(3)分离活跃数据。
(4)批量读取和延迟修改。
(5)读写分离。
(6)集群与分布式,集群是将多个请求分配到不同服务器(各个服务器功能一样)处理,而分布式是将一个请求分配到不同服务器(各个服务器功能可以不一样)处理。
3、高并发解决方案
(1)应用与静态资源分离。
(2)页面静态化。
(3)集群与分布式。
(4)反向代理
* 反向代理,简单说就是用户访问的地址不是返回实际资源的地址,一般是用做负载均衡、转发请求。
* 正向代理,简单说就是用户访问的地址就是返回实际资源的地址,一般是由于网络隔断需要代理,如“翻墙”。
(5)CDN
4、底层优化
(1)HTTP2协议。
(2)定制协议,如Google的Quic协议,其效率比TCP高,安全性比UDP高。
二、常见协议和标准
1、DNS
2、TCP
(1)三次握手与四次挥手。
* 客服端连接:closed->syn_send->established->fin_wait_1->fin_wait_2->time_wait->closed
* 服务端连接:listen->syn_rcvd->established->close_wait->last_ack->closed
(2)两个序号与三个标志位。
* seq数据序号,TCP每个字节都有一个序号,发送数据时会将数据的第一个序号发送给对方,接收方会按序号检查是否接收完整。
* ack确认号,表示接收端希望接收的下一个数据包起始序号,也就是接收端反馈给发送端ack代表的序号前面的数据已经成功接收。
* ACK确认位,只有ACK=1时ack才起作用,第一次发起请求时ACK=0。
* SYN同步位,表示现在是建立连接。
* FIN终止位,表示现在是释放连接。
(3)三次握手建立连接时,发送端再次发送确认的必要性
主要是为了防止已失效的连接请求,比如网络延迟原因造成很久才收到一个已失效的连接请求。
(4)四次挥手释放连接时,等待2MSL的意义
* 保证A发送的最有一个ACK能够到达B。这个ACK有可能丢失,因而使处在LAST-ACK状态的B收不到对已发送的FIN和ACK报文段的确认。B会超时重传这个FIN和ACK报文段,而A就能在2MSL时间内收到这个重传的ACK+FIN报文段,接着A重传一次确认。
* 若A在发送了最后一个ACK后连接立即变成CLOSED状态,那么C就可以立即占用该端口,那么C就可能向处在LAST-ACK状态的B发送连接请求而遭拒绝,也可能收到旧连接的数据。所以经过2MSL,就可以使连接持续的时间内所产生的所有报文都从网络中消失。
3、HTTP
三、详解Servlet
1、Servlet接口
(1)init(ServletConfig config)方法在容器启动时或Servlet第一次用到时才调用,且只会调用一次。
* ServletConfig就是对应web.xml中的Servlet配置信息。
* Tomcat中的Servletde的init方法是在StandardWrapper的initServlet方法中调用的。
(2)destroy()主要用于在Servlet销毁(一般只关闭服务器)时释放一些资源,且只会调用一次。
2、HttpServlet
(1)HttpServlet是根据http协议实现的Servlet的基类,实现了Servlet的service方法。
(2)在HttpServlet的service方法中,首先将ServletRequest和ServletResponse转换为HttpServletRequest和HttpServletResponse,然后根据http请求类型调用不同的处理方法。
(3)继承HttpServlet主要是重写doGet和doPost方法。
四、Tomcat分析
1、tomcat的结构
(1)Bootstrap:入口类,tomcat的入口main方法就在Bootstrap中,并由此创建CatAlina,并调用start。
(2)Catalina:管理类,里面的三个方法load、start、stop分别用来管理整个服务器Server的生命周期。
(3)Server:服务器,一个tomcat中只有一个Server,一个Server可以包含多个Service。
(4)Service:具体服务,一个Service只有一个Container,但可包含多个Connector(因为一个服务可以有多个连接,如同时提供http和https连接,也可以提供相同协议不同端口的连接)。
* Connector,负责网络连接、request/response的创建等。
* Container,具体处理Servlet。
2、启动过程
(1)Bootstrap启动
* 根据catalina.properties初始化ClassLoaders,包括commonLoader、(server)catalinaLoader、sharedLoader。
* 使用catalinaLoader加载并实例化Catalina,然后通过反射调用设置Catalina的ParentClassLoader为catalinaLoader。
* 根据命令参数,组合调用Catalina的setAwait、load、start等方法。
(2)Catalina启动
* 调用setAwait方法,设置await属性值,在start方法中的服务启动完后会根据await判断是否进入等待状态。
* 调用load方法,根据server.xml配置创建Server对象。
* 调用start方法,里面调用Server的start方法启动服务器,并注册关闭钩子。
* 最后根据await判断是否进入等待状态,若进入则调用Server的await方法,保证服务器处于运行状态。
(3)Server启动
* addService和removeService来添加和删除Service。
* 调用initInternal方法来初始化所有Service。
* 调用startInternal方法来启动所有Service。
(4)Service启动
* 调用initInternal方法来初始化所有container、executors、mapperListener和connectors。
* 调用startInternal方法来启动所有container、executors、mapperListener和connectors。
3、生命周期管理
(1)Lifecycle接口:tomcat通过Lifecycle接口统一管理生命周期,所有生命周期的组件都要实现Lifecycle接口。
* 定义了13种LifecycleEvent事件的类型。
* 定义了3个管理监听器的方法,用于添加、查找和删除LifecycleListener类型的监听器。
* 定义了4个生命周期方法,init、start、stop和destroy,用于执行生命周期的各个阶段的操作。
* 定义了2个获取当前状态的方法,状态枚举类型LifecycleState。
(2)LifecycleBase实现Lifecycle。
* 使用LifecycleSupport来实现监听器的管理。
* 提供init、start、stop和destory对应的模板方法initInternal、startInternal、stopInternal和destroyInternal由子类实现。
4、Container分析
(1)Container是tomcat的容器接口
* 默认实现类ContainerBase。
* 子接口Engine、Host、Context、Wrapper,并都对应一个继承了ContainerBase的实现类StandardXXX。
* 一个service子容器包含关系:一个Engine->多个Host->多个Context->多个Wrapper。
* Engine:引擎,用来管理多个站点,一个Service只能有一个Engine。
* Host:代表一个站点,也可以叫虚拟主机,通过配置Host就可以添加站点,因为一个ip可以对应多个域名。
* Context:代表一个应用程序,对应一个web.xml文件。
* Wrapper:每个Wrapper封装着一个Servlet。
(2)Container启动
* 除了最顶层的容器的init是被Service调用的,其它都是在start方法中通过判断初始化。
* start方法除了在父容器startInternal方法中调用,还会在addChild方法中调用,主要是因为Context和Wrapper是动态添加的。
* 在站点目录下(如默认的webapps目录)放一个war包就可以添加一个Context。在web.xml中配置一个Servlet就可以添加一个Wrapper。
* 启动主要过程:如果有Cluster和Realm则启动; 使用线程池启动所有子容器; 启动管道pipeline; 设置该容器生命周期状态STARTING;启动后台线程定时处理一些事情。
(3)具体容器启动内容
* Engine作为顶级容器被Service调用启动,在其initInternal方法中判断如果没有配置Realm,则设置一个默认的NullRealm。通过调用父类ContainerBase的startInternal来启动子容器。
* Host由Engine调用启动,检查Host的管道中是否有值加入Pipeline中。Host不是通过调用父类ContainerBase的startInternal来启动子容器,而是通过监听器HostConfig来部署生成Context,并在addChild方法中启动它。
* Context启动,通过监听器ContextConfig来解析web.xml生成Wrapper,并根据web.xml初始化配置的listener(若配置了ContextLoaderListener则会通过它初始化spring容器)、filter和配置了load-on-startup的Servlet(在生成的Wrapper中,且对应初始化springmvc容器)。
* Wrapper启动,用broadcaster发送通知用于JMX,调用setAvailable方法让Servlet有效。
(4)ContextConfig的webConfig()
* 读取各个jar模块的web-fragment.xml,排序所有读取到的fragments;
* 通过SPI查找所有的ServletContainerInitializer实现类;
* 处理所有的注解配置类并缓存;
* 所有的web-fragment.xml合并到web.xml中;
* 转换所有的JSP代码成Java代码;
* 将Web.xml配置转变成代码式的配置;
* 将所有的实现ServletContainerInitializer的类添加到StandardContext的initializers集合。
(5)Pipeline-Valve管道
* 每个管道都有一个特定的BaseValve且最后执行; 上层容器的管道BaseValve会调用下层容器的管道。
* Engine、Host、Context、Wrapper的管道中的BaseValve是StandardXXXValve。
* Pipeline的实现分为生命周期管理和处理请求两部分。
(6)Pipeline处理请求
* Connector收到请求后会调用顶层容器的Pipeline来处理,最后传递到Wrapper容器的管道中的StandardWrapperValve处理。
* StandardWrapperValve中创建了FilterChain,FilterChain中就包括我们配置的与请求相匹配的Filter和Servlet。
5、Connector分析
Connector主要作用是在其创建时创建ProtocolHandler,然后在生命周期的相关方法中调用ProtocolHandler的相关生命周期方法,请求的具体处理是在ProtocolHandler中。
(1)ProtocolHandler处理请求
* 不同的ProtocolHandler代表不同连接类型。如Http11Protocol是普通Socket连接,Http11NioProtocol是NioSocket连接。
* ProtocolHandler有3个非常重要的组件:Endpoint、Processor和Adapter。
(2)Endpoint处理Tcp协议
(3)Processor处理Http等应用层协议
(4)Adapter实现调用容器管道Pipeline处理请求
第二部分:SpringMVC
一、springMVC初体验
1、SpringMVC的Servlet
Tomcat启动时通过context容器根据web.xml生成Servlet的封装类Wrapper,并初始化spring容器(需配置)和Servlet对应的springmvc容器; 当context容器中的Connector收到请求后会调用顶层容器Engine的Pipeline来处理,通过管道最终到达请求相匹配的Filter和Servlet。
(1)HttpServletBean
* 继承HttpServlet,实现EnvironmentCapable, EnvironmentAware。
* 封装Servlet配置的参数,并通过BeanWrapper设置到DispatcherServlet的相关属性。
(2)FrameworkServlet
* 继承HttpServletBean,实现ApplicationContextAware。
* 初始化WebApplicationContext,即springmvc的容器:获取spring的根容器、设置WebApplicationContext并根据情况调用onRefresh方法、将WebApplicationContext设置到ServletContext中。
(3)DispatcherServlet
* 继承FrameworkServlet。
* 是springmvc的核心类,整个处理过程的顶层设计都在这里。
* onRefresh方法初始化九大组件; doService方法是处理请求的入口; doDispatch具体处理请求的方法。
* 九大组件:MultipartResolver、LocaleResolver、ThemeResolver、HandlerMapping、HandlerAdapter、HandlerExceptionResolver、RequestToViewNameTranslator、ViewResolver、FlashMapManager。
2、LocaleContextHolder和RequestContextHolder可以很方便获取相关信息。
二、springMVC组件分析
1、HandlerMapping
HandlerMapping的作用是根据request找到相应的处理器Handler和Interceptors。实现类AbstractHandlerMapping,以及AbstractHandlerMapping的子类AbstractUrlHandlerMapping和AbstractHandlerMethodMapping。
(1)AbstractHandlerMapping
* 继承了WebApplicationObjectSupport,间接实现了ApplicationContextAware,所以在springmvc容器启动后就会调用AbstractHandlerMapping的initApplicationContext方法。
* initApplicationContext方法里面包括三个方法:extendInterceptors(this.interceptors)提供子类添加修改interceptors的模板方法,detectMappedInterceptors(this.mappedInterceptors)把配置的MappedInterceptor类型的bean添加到mappedInterceptors中,initInterceptors()将interceptors中的对象按类型添加到MappedInterceptors或adaptedInterceptors中。
* 属性interceptors用于配置Interceptor; 属性mappedInterceptors保存需要与url匹配的Interceptor,从interceptors获取或是配置的MappedInterceptor类型的bean; 属性adaptedInterceptors不需要匹配的Interceptor,只从interceptors获取。
(2)AbstractUrlHandlerMapping
* AbstractUrlHandlerMapping设计了整体结构,完成了查找Handler的具体逻辑。
* 保存url与Handler对应关系的handlerMap,这个handlerMap由子类完成初始化。
* handlerMap初始化分两种:一种是手工在配置文件里注册; 另一种是根据容器中bean的beanName和alias是不是以"/"开头、是否实现Controller接口或注释@Controller筛选出来。
(3)AbstractHandlerMethodMapping
* AbstractHandlerMethodMapping是将Method作为Handler,是现在用得最多的一种Handler,比如@RequestMapping注释的方法就是HandlerMethod。
* RequestCondition匹配条件接口,其实现类CompositeRequestCondition是组合多个XXXRequestCondition条件,而XXXRequestCondition类都代表一种匹配条件。如请求方法匹配RequestMethodsRequestCondition、请求参数匹配ParamsRequestCondition。
* AbstractHandlerMethodMapping实现了InitializingBean接口,初始化是从容器中筛选有@Controller或@RequestMapping注释的bean,然后获取所有符合要求的方法,最后注册到Map中。
* lookupHandlerMethod方法通过排序获取第一个来得到最匹配的HandlerMethod。
2、HandlerAdapter
HandlerAdapter的作用是使用Handler进行请求处理。实现类HttpRequestHandlerAdapter、SimpleServletHandlerAdapter和SimpleControllerHandlerAdapter分别适配HttpRequestHandler、Servlet和Controller,而RequestMappingHandlerAdapter所处理的Handler可以是任意的方法。
(1)RequestMappingHandlerAdapter大致处理流程
* 备好handler需要的参数,这个最复杂的一步。参数来源包括:request、cookie、session、FlashMap、@SessionAttribute、@ModelAttribute。
* 使用handler处理请求,这是最简单的一步,直接使用反射调用。
* 处理返回值,也就是将不同类型的返回值统一处理成ModelAndView类型。
(2)RequestMappingHandlerAdapter初始化
* RequestMappingHandlerAdapter实现了InitializingBean接口,通过afterPropertiesSet方法初始化。
* 初始化内容:argumentResolvers、initBinderArgumentResolvers、returnValueHandlers和@ControllerAdvice注释类相关的modelAttributeAdviceCache、initBinderAdviceCache以及responseBodyAdvice。
(3)RequestMappingHandlerAdapter处理请求
* handleInternal是处理请求的入口方法,主要包括checkRequest和invokeHandlerMethod两个方法。
* checkRequest包括检查请求方法类型、检查是否session存在和设置response缓存的过期时间。
* invokeHandlerMethod方法首先使用request和response创建ServletWebRequest,接着初始化WebDataBinderFactory、ModelFactory和ServletInvocableHandlerMethod。
(4)WebDataBinderFactory
* 其创建过程就是将符合条件的@InitBinder注释的方法找出来。
* 用于创建WebDataBinder,在参数解析和更新Model时会用到WebDataBinder。
(5)ModelFactory
* 用于在处理器具体处理之前对Model进行初始化,把SessionAttributes和@ModelAttribute对应的值设置到Model中。
* 用于在处理完请求后对Model参数进行更新。
(6)ServletInvocableHandlerMethod
* 实际处理请求,参数绑定、处理请求以及返回值处理都在这里面完成。
* 处理步骤:新建整个过程的参数载体ModelAndViewContainer用于保存Model和View; 执行请求; 处理完请求后创建ModelAndView。
(7)HandlerMethodArgumentResolver
* 为处理器解析参数,实现类分为两种:XXXMethodArgumentResolver和XXXMethodProcessor,XXX代表解析的参数类型。
* XXXMethodArgumentResolver表示一个参数解析器,而XXXMethodProcessor除了解析参数外还可以处理相应类型的返回值。
(8)HandlerMethodReturnValueHandler
* 处理返回值:添加相应值到Model; 设置ViewName; 如果请求已经处理完则设置ModelAndViewContainer的requestHandled为true。
(9)@InitBinder
* 对@Controller的方法提供参数WebDataBinder。
* WebDataBinder可以注册校验器Validator应用到当前Controller。
* WebDataBinder可以注册属性编辑器PropertyEditor应用到当前Controller。
(10)@ControllerAdvice
* @ControllerAdvice注解的类对控制器提供一个全局增强器,其实就是向RequestMappingHandlerAdapter中注册处理方法。
* 配合@ExceptionHandler、@ModelAttribute、@InitBinder注解的方法,可对所有@RequestMapping的方法进行增强。
3、HandlerExceptionResolver
HandlerExceptionResolver的作用是解析对请求做处理的过程中产生的异常,而render渲染产生的异常不归它管。
(1)使用SimpleMappingExceptionResolver,使用这种方式具有集成简单、有良好的扩展性、对已有代码没有入侵性等优点,但该方法仅能获取到异常信息,若在出现异常时,对需要获取除异常以外的数据的情况不适用。
(2)实现异常处理接口HandlerExceptionResolver,自定义自己的异常处理器,能获取异常外的其它信息。
(3)使用@ExceptionHandler注解实现异常处理,更加灵活,可以控制异常捕获类型、作用范围。
4、ViewResolver
ViewResolver的作用是根据视图名和Locale解析成View类型的视图。
(1)AbstractCachingViewResolver使用最多,它可以换成解析过的视图View。
(2)ContentNegotiatingViewResolver使用其它ViewResolver解析视图View,根据request的Content-Type和url后缀来确定最优视图View。
(3)BeanNameViewResolver使用视图名作为beanName在springmvc容器中查找视图View。
(4)ViewResolverComposite封装了多个ViewResolver,成功解析得到视图View就返回。
5、RequestToViewNameTranslator
RequestToViewNameTranslator的作用是从request获取viewName,在springmvc容器中只能配置一个。
6、LocaleResolver
LocaleResolver的作用是从request中解析出Locale。
7、ThemeResolver
ThemeResolver的作用是从request解析出主题名,然后ThemeSource根据主题名找到主题Theme。
8、MultipartResolver
MultipartResolver的作用是判断request是不是multipart/form-data类型,是则把request包装成MultipartHttpServletRequest。
9、FlashMapManager
FlashMapManager的作用是在redirect中传递参数,默认SessionFlashMapManager通过session实现传递。
三、异步请求
1、Servlet3.0规范新增了对异步请求的支持。
(1)异步请求的核心原理主要分两大类,一类是轮询,另一类是长连接。轮询方式对资源的浪费比较大,Servlet采用长连接的方式。
(2)AsyncContext是异步请求上下文,异步请求主要使用AsyncContext进行操作,它是请求处理过程中调用Request的startAsync方法返回的,多次调用startAsync返回的同一个AsyncContext。
(3)AsyncListener异步请求监听器,需要添加到AsyncContext中,可以监听请求complete、timeout、error和startAsync,但是第一次startAsync无法监听到,因为AsyncContext还不存在。
2、SpringMVC中的异步请求
(1)FrameworkServlet中给当前请求的WebAsyncManager添加CallableProcessingIntercept类型的拦截器。
(2)RequestMappingHandlerAdapter的invokeHandleMethod方法提供了对异步请求的核心支持。
* 创建AsyncWebRequest并设置超时时间,可配置RequestMappingHandlerAdapter的asyncRequestTimeout属性。
* 对当前请求的WebAsyncManager设置taskExecutor、AsyncWebRequest、callableInterceptors和deferredResultInterceptors,除了AsyncWebRequest,其它都通过RequestMappingHandlerAdapter配置。
* 如果当前异步请求已经处理出了结果,则解析返回。
* 如果当前请求已经启动了异步处理,则返回null。
(3)异步处理返回值处理器,一共四种,它们主要是使用WebAsyncManager启动异步处理,后面对返回值进行分析。
(4)在DispatchServlet的doDispatch方法中会检查是否已启动异步处理,是则直接返回,当异步处理完成后会重新发出一个相同的请求(这里就会造成请求会被拦截器多次拦截的问题,也会有FlashMap的问题)。