微服务基础知识点学习笔记(持续更新)
微服务基础知识点学习笔记(持续更新)
Conrtoller层
整体包括:HTTP协议,JavaWeb三大组件(filter、servlet、listener)、SpringMVC(SpringMVC的执行流程、常用配置、SpringMVC注解的使用)、OpenFeign。
HTTP协议(Hyper Text Transfer Protocol:超文本传输协议)
在Web应用中,浏览器请求一个URL,服务器就把生成的HTML网页发送给浏览器,而浏览器和服务器之间的传输协议是HTTP。而HTTP协议又是一个基于TCP/IP协议来传输数据。
常用的HTTP Header
HTTP头以Header: Value
形式表示的,常用的有:
- Host: 表示请求的主机名,因为一个服务器上可能运行着多个网站,因此,Host表示浏览器正在请求的域名;
- User-Agent: 标识客户端本身,例如Chrome浏览器的标识类似
Mozilla/5.0 ... Chrome/79
,IE浏览器的标识类似Mozilla/5.0 (Windows NT ...) like Gecko
; - Accept:表示浏览器能接收的资源类型,如
text/*
,image/*
或者*/*
表示所有; - Accept-Language:表示浏览器偏好的语言,服务器可以据此返回不同语言的网页;
- Accept-Encoding:表示浏览器可以支持的压缩类型,例如
gzip, deflate, br
。
HTTP常见的响应码
其中2xx
表示成功,3xx
表示重定向,4xx
表示客户端引发的错误,5xx
表示服务器端引发的错误。数字是给程序识别,文本则是给开发者调试使用的。常见的响应代码有:
- 200 OK:表示成功;
- 301 Moved Permanently:表示该URL已经永久重定向;
- 302 Found:表示该URL需要临时重定向;
- 304 Not Modified:表示该资源没有修改,客户端可以使用本地缓存的版本;
- 400 Bad Request:表示客户端发送了一个错误的请求,例如参数无效;
- 401 Unauthorized:表示客户端因为身份未验证而不允许访问该URL;
- 403 Forbidden:表示服务器因为权限问题拒绝了客户端的请求;
- 404 Not Found:表示客户端请求了一个不存在的资源;
- 500 Internal Server Error:表示服务器处理时内部出错,例如因为无法连接数据库;
- 503 Service Unavailable:表示服务器此刻暂时无法处理请求。
服务器经常返回的HTTP Header
- Content-Type:表示该响应内容的类型,例如
text/html
,image/jpeg
; - Content-Length:表示该响应内容的长度(字节数);
- Content-Encoding:表示该响应压缩算法,例如
gzip
; - Cache-Control:指示客户端应如何缓存,例如
max-age=300
表示可以最多缓存300秒。
通常浏览器获取的第一个资源是HTML网页,在网页中,如果嵌入了JavaScript、CSS、图片、视频等其他资源,浏览器会根据资源的URL再次向服务器请求对应的资源。HTTP是以客户端的身份去请求服务器资源,以服务器的身份响应客户端请求,同时编写服务器程序来处理客户端请求通常就称之为Web开发。
Servlet
简介
在JavaEE平台上,处理TCP连接,解析HTTP协议这些底层工作统统扔给现成的Web服务器去做,我们只需要把自己的应用程序跑在Web服务器上。为了实现这一目的,JavaEE提供了Servlet API,使用Servlet API编写自己的Servlet来处理HTTP请求,Web服务器实现Servlet API接口,实现底层功能:
┌───────────┐│My Servlet │├───────────┤│Servlet API│
┌───────┐ HTTP ├───────────┤
│Browser│<──────>│Web Server │
└───────┘ └───────────┘
一个Servlet总是继承自HttpServlet
,然后覆写doGet()
或doPost()
方法。注意到doGet()
方法传入了HttpServletRequest
和HttpServletResponse
两个对象,分别代表HTTP请求和响应。我们使用Servlet API时,并不直接与底层TCP交互,也不需要解析HTTP协议,因为HttpServletRequest
和HttpServletResponse
就已经封装好了请求和响应。
同时,我们编写的Servlet并不是直接运行,而是由Web服务器加载后创建实例运行,所以,类似Tomcat这样的Web服务器也称为Servlet容器
。
在Servlet容器中运行的Servlet具有如下特点:
- 无法在代码中直接通过new创建Servlet实例,必须由Servlet容器自动创建Servlet实例;
- Servlet容器只会给每个Servlet类创建唯一实例;
- Servlet容器会使用多线程执行
doGet()
或doPost()
方法。
结合多线程可得出:
- 在Servlet中定义的实例变量会被多个线程同时访问,要注意线程安全;
HttpServletRequest
和HttpServletResponse
实例是由Servlet容器传入的局部变量,它们只能被当前线程访问,不存在多个线程访问的问题;- 在
doGet()
或doPost()
方法中,如果使用了ThreadLocal
,但没有清理,那么它的状态很可能会影响到下次的某个请求,因为Servlet容器很可能用线程池实现线程复用。
因此编写Servlet必须考虑多线程同步,需要同步的必须要同步。
多servlet的WebApp
一个WebApp是由多个Servlet组成,每个servlet类似于MVC中的控制器可以通过注解来表示自己可以处理的请求路径:
@WebServlet(urlPatterns = "/hello") public class HelloServlet extends HttpServlet {... }
上述
HelloServlet
能处理/hello
这个路径的请求。因为浏览器发送请求的时候,还会有请求方法(HTTP Method):即GET、POST、PUT等不同类型的请求。因此,要处理GET请求,我们要覆写
doGet()
方法:@WebServlet(urlPatterns = "/hello") public class HelloServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {...} }
类似的,要处理POST请求,就需要覆写
doPost()
方法。否则就会直接返回报错。
HttpServletRequest
HttpServletRequest
封装了一个HTTP请求,它实际上是从ServletRequest
继承而来。最早设计Servlet时,设计者希望Servlet不仅能处理HTTP,也能处理类似SMTP等其他协议,因此,单独抽出了ServletRequest
接口,但实际上除了HTTP外,并没有其他协议会用Servlet处理,所以这是一个过度设计。
我们通过HttpServletRequest
提供的接口方法可以拿到HTTP请求的几乎全部信息,常用的方法有:
- getMethod():返回请求方法,例如,
"GET"
,"POST"
; - getRequestURI():返回请求路径,但不包括请求参数,例如,
"/hello"
; - getQueryString():返回请求参数,例如,
"name=Bob&a=1&b=2"
; - getParameter(name):返回请求参数,GET请求从URL读取参数,POST请求从Body中读取参数;
- getContentType():获取请求Body的类型,例如,
"application/x-www-form-urlencoded"
; - getContextPath():获取当前Webapp挂载的路径,对于ROOT来说,总是返回空字符串
""
; - getCookies():返回请求携带的所有Cookie;
- getHeader(name):获取指定的Header,对Header名称不区分大小写;
- getHeaderNames():返回所有Header名称;
- getInputStream():如果该请求带有HTTP Body,该方法将打开一个输入流用于读取Body;
- getReader():和getInputStream()类似,但打开的是Reader;
- getRemoteAddr():返回客户端的IP地址;
- getScheme():返回协议类型,例如,
"http"
,"https"
;
此外,HttpServletRequest
还有两个方法:setAttribute()
和getAttribute()
,可以给当前HttpServletRequest
对象附加多个Key-Value,相当于把HttpServletRequest
当作一个Map<String, Object>
使用。
调用HttpServletRequest
的方法时,注意务必阅读接口方法的文档说明,因为有的方法会返回null
,例如getQueryString()
的文档就写了:
... This method returns null if the URL does not have a query string...
HttpServletResponse
HttpServletResponse
封装了一个HTTP响应。由于HTTP响应必须先发送Header,再发送Body,所以,操作HttpServletResponse
对象时,必须先调用设置Header的方法,最后调用发送Body的方法。
常用的设置Header的方法有:
- setStatus(sc):设置响应代码,默认是
200
; - setContentType(type):设置Body的类型,例如,
"text/html"
; - setCharacterEncoding(charset):设置字符编码,例如,
"UTF-8"
; - setHeader(name, value):设置一个Header的值;
- addCookie(cookie):给响应添加一个Cookie;
- addHeader(name, value):给响应添加一个Header,因为HTTP协议允许有多个相同的Header;
写入响应时,需要通过getOutputStream()
获取写入流,或者通过getWriter()
获取字符流,二者只能获取其中一个。
写入响应前,无需设置setContentLength()
,因为底层服务器会根据写入的字节数自动设置,如果写入的数据量很小,实际上会先写入缓冲区,如果写入的数据量很大,服务器会自动采用Chunked编码让浏览器能识别数据结束符而不需要设置Content-Length头。
但是,写入完毕后调用flush()
却是必须的,因为大部分Web服务器都基于HTTP/1.1协议,会复用TCP连接。如果没有调用flush()
,将导致缓冲区的内容无法及时发送到客户端。此外,写入完毕后千万不要调用close()
,原因同样是因为会复用TCP连接,如果关闭写入流,将关闭TCP连接,使得Web服务器无法复用此TCP连接。
写入完毕后对输出流调用flush()而不是close()方法!
有了HttpServletRequest
和HttpServletResponse
这两个高级接口,我们就不需要直接处理HTTP协议。注意到具体的实现类是由各服务器提供的,而我们编写的Web应用程序只关心接口方法,并不需要关心具体实现的子类。
Servlet多线程模型
一个Servlet类在服务器中只有一个实例,但对于每个HTTP请求,Web服务器会使用多线程执行请求。因此,一个Servlet的doGet()
、doPost()
等处理请求的方法是多线程并发执行的。如果Servlet中定义了字段,要注意多线程并发访问的问题:
public class HelloServlet extends HttpServlet {private Map<String, String> map = new ConcurrentHashMap<>();protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 注意读写map字段是多线程并发的:this.map.put(key, value);}
}
对于每个请求,Web服务器会创建唯一的HttpServletRequest
和HttpServletResponse
实例,因此,HttpServletRequest
和HttpServletResponse
实例只有在当前处理线程中有效,它们总是局部变量,不存在多线程共享的问题。
重定向与转发
重定向Redirect:
重定向是指浏览器请求一个URL时,服务器返回一个重定向指令,需要浏览器用新的URL重新发出请求。这个过程就是302响应
。如图所示:
┌───────┐ GET /hi ┌───────────────┐
│Browser│ ────────────> │RedirectServlet│ 第一次发出GET /hi请求,服务器返回重定向302相应并给予新的URL。
│ │ <──────────── │ │
└───────┘ 302 └───────────────┘┌───────┐ GET /hello ┌───────────────┐
│Browser│ ────────────> │ HelloServlet │ 第二次请求使用新的GET /hello请求,成功获取<html>资源。
│ │ <──────────── │ │
└───────┘ 200 <html> └───────────────┘
转发Forward:
转发是指在服务器内部进行重新调度。如图所示:
┌────────────────────────┐│ ┌───────────────┐ ││ ────>│ForwardServlet │ │
┌───────┐ GET /morning │ └───────────────┘ │
│Browser│ ──────────────> │ │ │
│ │ <────────────── │ ▼ │
└───────┘ 200 <html> │ ┌───────────────┐ ││ <────│ HelloServlet │ ││ └───────────────┘ ││ Web Server │└────────────────────────┘
ServletContext
什么是ServletContext
要理解ServletContext就必须和Cookie、Session做一个对比,如下图:
你可以把它想象成一个公用的空间,可以被所有的客户访问,也就是说A客户端可以访问D,B客户端可以访问D,C客户端也可以访问D。
总结可知:
- WEB容器在启动时,它会为每个Web应用程序都创建一个对应的ServletContext,它代表当前Web应用。并且它被所有客户端共享。
- ServletContext对象可以通过
ServletConfig.getServletContext()
方法获得对ServletContext对象的引用,也可以通过this.getServletContext()
方法获得其对象的引用。 - 由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象。
- 当web应用关闭、Tomcat关闭或者Web应用reload的时候,ServletContext对象会被销毁
使用ServletContext
(1) 如何得到ServletContext对象
this.getServletContext();
this.getServletConfig().getServletContext();
(2) 你可以把它想象成一张表,这个和Session非常相似:每一行就是一个属性,如下:
名字(String) | 值(Object) |
---|---|
- 添加属性:
setAttribute(String name, Object obj);
- 得到值:
getAttribute(String name)
,这个方法返回Object - 删除属性:
removeAttribute(String name)
(3) 生命周期
ServletContext中的属性的生命周期从创建开始,到服务器关闭结束。
ServletContext是存在于服务器内存中的一个公共空间,除非关闭或重启服务器才会失去其中的数据。
使用Session和Cookie
因为HTTP是无状态协议,Web应用程序无法识别两次HTTP请求是否为同一个浏览器发出。所以需要使用Session和Cookie实现这一机制。
Session
浏览器第一次访问服务器的时候会被分配一个唯一的Session ID,如果用户在一段时间内没有访问服务器,那么Session会自动失效,下次即使带着上次分配的Session ID访问,服务器也认为这是一个新用户,会分配新的Session ID。
我们可以在session里面保存用户登录的信息,再次访问servlet时可以尝试在session中找到已经登录过的用户,可以实现识别不同的HTTP请求是否为用一个浏览器发出。所有的servlet都在维护同一个session(相同的内存空间)如图:
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐│ ┌───────────────┐ │| ┌───>│ IndexServlet │<──────────┐ |│ │ └───────────────┘ ▼ │
┌───────┐ | │ ┌───────────────┐ ┌────────┐|
│Browser│──┼─┼───>│ SignInServlet │<────>│Sessions││
└───────┘ | │ └───────────────┘ └────────┘|│ │ ┌───────────────┐ ▲ │| └───>│SignOutServlet │<──────────┘ |│ └───────────────┘ │└ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
Cookie
在当前浏览器请求的servlet第一次调用getSession()时,就会创建一个SessionID,然后通过JSESSIONID
的Cookie发送给浏览器。
Cookie 是存储在客户端计算机上的文本文件,并保留了各种跟踪信息。Java Servlet 显然支持 HTTP Cookie。
识别返回用户包括三个步骤:
- 服务器脚本向浏览器发送一组 Cookie。例如:姓名、年龄或识别号码等。
- 浏览器将这些信息存储在本地计算机上,以备将来使用。
- 当下一次浏览器向 Web 服务器发送任何请求时,浏览器会把这些 Cookie 信息发送到服务器,服务器将使用这些信息来识别用户。
Filter
在一个比较复杂的Web应用程序中,通常都有很多URL映射,对应的,也会有多个Servlet来处理URL。为了把一些公用逻辑从各个Servlet中抽离出来,JavaEE的Servlet规范还提供了一种Filter组件,即过滤器,它的作用是,在HTTP请求到达Servlet之前,可以被一个或多个Filter预处理,类似打印日志、登录检查等逻辑,完全可以放到Filter中。
- 编写方法:
编写Filter时,必须实现Filter
接口,在doFilter()
方法内部,要继续处理请求,必须调用chain.doFilter()
。最后,用@WebFilter
注解标注该Filter需要过滤的URL。这里的/*
表示所有路径。如果一定要给每个Filter指定顺序,就必须在web.xml
文件中对这些Filter再配置一遍。
例如,我们编写一个最简单的EncodingFilter,它强制把输入和输出的编码设置为UTF-8:
@WebFilter(urlPatterns = "/*")
public class EncodingFilter implements Filter {public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {System.out.println("EncodingFilter:doFilter");request.setCharacterEncoding("UTF-8");response.setCharacterEncoding("UTF-8");chain.doFilter(request, response);}
}
再写一个针对特殊路径的过滤器:
@WebFilter("/user/*")
public class AuthFilter implements Filter {public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {System.out.println("AuthFilter: check authentication");HttpServletRequest req = (HttpServletRequest) request;HttpServletResponse resp = (HttpServletResponse) response;if (req.getSession().getAttribute("user") == null) {// 未登录,自动跳转到登录页:System.out.println("AuthFilter: not signin!");resp.sendRedirect("/signin");} else {// 已登录,继续处理:chain.doFilter(request, response);}}
}
注意到AuthFilter
只过滤以/user/
开头的路径,因此:
- 如果一个请求路径类似
/user/profile
,那么它会被上述3个Filter依次处理; - 如果一个请求路径类似
/test
,那么它会被上述2个Filter依次处理(不会被AuthFilter处理)。
再注意观察AuthFilter
,当用户没有登录时,在AuthFilter
内部,直接调用resp.sendRedirect()
发送重定向,且没有调用chain.doFilter()
,因此,当用户没有登录时,请求到达AuthFilter
后,不再继续处理,即后续的Filter和任何Servlet都没有机会处理该请求了。
可见,Filter可以有针对性地拦截或者放行HTTP请求。
再次提醒! 如果Filter要使请求继续被处理,就一定要调用chain.doFilter()!
SpringMVC
具体内容转到我的Spring知识点总结博客
微服务基础知识点学习笔记(持续更新)相关推荐
- 重拾CCNA,学习笔记持续更新ing......(4)
重拾CCNA,学习笔记持续更新ing......(4) 路由器作用功能的经典解说(笑)(非原创) 假设你的名字叫小不点,你住在一个大院子里,你的邻居有很多小伙伴,在门口传达室还有个看大门的李大爷,李大 ...
- 《SpringCloud微服务架构》学习笔记
一.SpringCloud概述 说到SpringCloud,相信大家都不陌生,它主要是用来管理微服务的,说直白有点,它就是基于SpringBoot实现的一套微服务治理工具包,它并不是一个框架,而是一系 ...
- Admin.NET管理系统(vue3等前后端分离)学习笔记--持续更新
我的学习笔记 - 9iAdmin.NET 欢迎学习交流 (一)前端笔记 1.1 关于.env的设置 1.2 关于路由模式问题 1.3 关于 vue.config.ts 1.4 关于 打包(pnpm r ...
- 记微服务架构实战学习笔记
架构演进和分布式系统基础知识 1.传统架构演进到分布式架构 简介:讲解单机应用和分布式应用架构演进基础知识 (画图) 高可用 LVS+keepalive 1.单体应用:开发速度慢启动时间长依赖庞大等等 ...
- 阿里巴巴微服务开源项目盘点(持续更新)
大前端.微服务.数据库.更多精彩,尽在开发者分会场 [Apache Dubbo] Apache Dubbo 是一款高性能.轻量级的开源Java RPC框架,是国内影响力最大.使用最广泛的开源服务框架之 ...
- 专升本 计算机 公共课学习笔记(持续更新中...)
计算机公共课学习笔记 第一章 计算机基础知识(30分) 1.计算机概述 计算机(Computer)的起源与发展 计算机(Computer)也称"电脑",是一种具有计算功能.记忆功能 ...
- JS逆向学习笔记 - 持续更新中
JS逆向学习笔记 寻找深圳爬虫工作,微信:cjh-18888 文章目录 JS逆向学习笔记 一. JS Hook 1. JS HOOK 原理和作用 原理:替换原来的方法. (好像写了句废话) 作用: 可 ...
- typescript-----javascript的超集,typescript学习笔记持续更新中......
Typescript,冲! Typescript 不是一门全新的语言,Typescript是 JavaScript 的超集,它对 JavaScript进行了一些规范和补充.使代码更加严谨. 一个特别好 ...
- 计算机网络:学习笔记(持续更新)
文章目录 前言 1.1 计算机网络基本概念 什么是计算机网络? 什么是网络协议? 1.2 计算机网络结构 计算机网络结构 网络边缘 接入网络(物理介质) 网络核心(核心网络) Internet结构 1 ...
最新文章
- WordPress中的cookie 机制
- SAP成都研究院C4C光明左使:SAP Cloud for Customer 使用SAP UI5的独特之处
- 你确定你真的理解“双亲委派“了吗?!
- 部署Vista需要了解的十大事项
- 从19本书中选取五本,并且要求这五本互相不相邻,一共有多少种方法?
- 恐怖黎明 联网显示无法连接服务器,豪横的刷刷刷 2021年最值得体验的暗黑类游戏...
- centos7设置静态IP地址方法
- [转]Cryengine渲染引擎剖析
- 计算机格式化没有fat32,windows里面没有FAT32格式化命令
- 小迪-65-内网安全
- 同城跑腿微信小程序制作步骤_分享下同城跑腿小程序的作用
- 金山打字通83字/分
- 35,UC(14) .
- 无法访问您试图使用的功能所在的网络位置 无法找到vcredist.msi的解决办法
- 基于非结构化的数据管理探究
- 爬百度贴吧并保存链接
- Java-正则表达式:匹配特定字符开头,数字结尾的任一字符串
- 李家同《让高墙倒下吧》
- 【高保真原型制作】上海道宁为您带来适用于所有数字产品的简单的​交互式原型制作工具——ProtoPie
- 基于AndroidJava的食谱菜谱菜品APP设计
热门文章
- 劳动保障职业学院计算机专业,北京劳动保障职业学院2020录取分数线(附2017-2020年分数线)...
- 聊一聊推荐系统中ExploitExplore算法
- SSH密码暴力破解及防御实战
- 论开学第三个月干了点啥
- IntelliJ IDEA使用教程(动图详解):实时代码模板的使用
- 制作 macOS High Sierra U盘
- 机器学习中SVM的损失函数,向量积
- h5调用支付宝 php支付源码,友价源码如何集成支付宝H5接口(即支付宝手机支付接口)...
- 4个月学前端找不到工作正常吗?什么原因?
- 《零基础学C语言》前言