JavaWeb基础
1. 什么是 Servlet?
Servlet 是在服务器上运行的小程序。一个 servlet 就是一个 Java 类,并且可以通过 “请求—响应” 编程模式来访问的这个驻留在服务器内存里的 servlet 程序。
2. Servlet 类的继承关系
3. Servlet 实现方式
实现 javax.servlet.Servlet 接口
继承 javax.servlet.GenericServlet 类
继承 javax.servlet.http.HttpServlet 类
通常会去继承 HttpServlet 类来完成 Servlet
4. Tomcat 容器等级
Tomcat 的容器分为4个等级,Servlet 的容器管理 Context 容器,一个 Context 对应一个 Web 工程。
5. Servlet 执行流程
主要描述了从浏览器到服务器,再从服务器到浏览器的整个执行过程。
1.浏览器请求
浏览器向服务器请求时,服务器不会直接执行我们的类,而是到 web.xml 里寻找路径名。
① 浏览器输入访问路径后,携带了请求行,头,体
② 根据访问路径找到已注册的 servlet 名称
③ 根据映射找到对应的 servlet 名
④ 根据根据 servlet 名找到我们全限定类名,既我们自己写的类
2.服务器创建对象
① 服务器找到全限定类名后,通过反射创建对象,同时也创建了 servletConfig,里面存放了一些初始化信息(注意服务器只会创建一次 servlet 对象,所以 servletConfig 也只有一个)
3.调用 init 方法
① 对象创建好之后,首先要执行 init 方法,但是我们发现我们自定义类下没有 init 方法,所以程序会到其父类 HttpServlet 里找
② 我们发现 HttpServlet 里也没有 init 方法,所以继续向上找,既向其父类 GenericServlet 中继续寻找,在 GenericServlet 中我们发现了 init 方法,则执行 init 方法(对接口 Servlet 中的 init 方法进行了重写)
注意: 在 GenericServlet 中执行 public void init(ServletConfig config) 方法的时候,又调用了自己无参无方法体的 init() 方法,其目的是为了方便开发者,如果开发者在初始化的过程中需要实现一些功能,可以重写此方法。
4.调用 service 方法
接着,服务器会先创建两个对象:ServletRequest 请求对象和 ServletResponse 响应对象,用来封装浏览器的请求数据和封装向浏览器的响应数据
① 接着服务器会默认在我们写的类里寻找 service(ServletRequest req, ServletResponse res) 方法,但是 DemoServlet 中不存在,那么会到其父类中寻找
② 到父类 HttpServlet 中发现有此方法,则直接调用此方法,并将之前创建好的两个对象传入
③ 然后将传入的两个参数强转,并调用 HttpServlet 下的另外个 service 方法
④ 接着执行 service(HttpServletRequest req, HttpServletResponse resp)
方法,在此方法内部进行了判断请求方式,并执行 doGet 和 doPost,但是 doGet 和 doPost 方法已经被我们自己重写了,所以会执行我们重写的方法
看到这里,你或许有疑问:为什么我们不直接重写 service 方法? 因为如果重写 service 方法的话,我们需要将强转,以及一系列的安全保护判断重新写一遍,会存在安全隐患。
4.向浏览器响应
6. Servlet 生命周期
- 加载和实例化:Servlet 容器负责加载和实例化 Servlet 对象。
- 初始化:
void init(ServletConfig servletConfig)
Servlet 对象创建之后马上执行的初始化方法,只执行一次。 - 请求处理:
void service(ServletRequest servletRequest, ServletResponse servletResponse)
每次处理请求都是在调用这个方法,它会被调用多次 - 销毁:
void destroy()
在 Servlet 被销毁之前调用,负责释放 Servlet 对象占用的资源的方法
服务器执行流程
- Servlet 类由自己编写,但对象由服务器来创建,并由服务器来调用相应的方法。
- 服务器启动时 ( web.xml 中配置
load-on-startup=1
,默认为0 ) 或者第一次请求该 Servlet 时,就会初始化一个 Servlet 对象,也就是会执行初始化方法 init(ServletConfig conf)。 - 该 Servlet 对象去处理所有客户端请求,在
service(ServletRequest req,ServletResponse res)
方法中执行。 - 最后服务器关闭时,才会销毁这个 Servlet 对象,执行 destroy() 方法。
一些问题
Servlet 何时创建? 答:默认第一次访问 Servlet 时创建该对象(调用 init() 方法)
Servlet何时销毁?答:服务器关闭 Servlet 就销毁了(调用 destroy() 方法)
每次访问必须执行的方法是什么?答:public void service(ServletRequest arg0, ServletResponse arg1)
7. Tomcat 装载 Servlet 的三种情况
Servlet 容器启动时自动装载某些 Servlet,实现它只需要在 web.xml 文件中的
<servlet></servlet>
之间添加以下代码:1
<load-on-startup>1</load-on-startup>
其中,数字越小表示优先级越高。启动和关闭 Tomcat:优先级高的先启动也先关闭。
客户端首次向某个 Servlet 发送请求。
Servlet 类被修改后,Tomcat 容器会重新装载 Servlet。
8. forward 和 redirect
Servlet 中主要有两种实现跳转的方式:forward 与 redirect 方式。
forward 是服务器内部的重定向,服务器直接访问目标地址的 URL,把那个 URL 的响应内容读取过来,而客户端并不知道,因此在客户端浏览器的地址栏中不会显示转向后的地址,还是原来的地址。由于在整个定向的过程中用的是同一个 Request,因此 forward 会将 Request 的信息带到被定向的 JSP 或 Servlet 中使用。
redirect 则是客户端的重定向,是完全的跳转,即客户端浏览器会获取到跳转后的地址,然后重新发送请求,因此浏览器中会显示跳转后的地址。同事,由于这种方式比 forward 方式多了一次网络请求,因此其效率要低于 forward 方式。需要注意的是,客户端的重定向可以通过设置特定的 HTTP 头或改写 JavaScript 脚本实现。
鉴于以上的区别,一般当 forward 方式可以满足需求时,尽可能地使用 forward 方式。但在有些情况下,例如,需要跳转到下一个其他服务器上的资源,则必须使用 redirect 方式。
引申:filter的作用是什么?主要实现什么方法?
filter 使用户可以改变一个 request 并且修改一个 response。filter 不是一个 Servlet,它不能产生一个 response,但它能够在一个 request 到达 Servlet 之前预处理 request,也可以在离开 Servlet 时处理 response。filter 其实是一个 “Servlet Chaining” (Servler 链)。
一个 filter 的作用包括以下几个方面:
- 在 Servlet 被调用之前截获
- 在 Servlet 被调用之前检查 Servlet Request
- 根据需要修改 Request 头和 Request 数据
- 根据需要修改 Response 头和 Response 数据
- 在 Servlet 被调用之后截获
9. Jsp 和 Servlet 的区别
不同之处在哪?
- Servlet 在 Java 代码中通过 HttpServletResponse 对象动态输出 HTML 内容
- JSP 在静态 HTML 内容中嵌入 Java 代码,Java 代码被动态执行后生成 HTML 内容
各自的特点
- Servlet 能够很好地组织业务逻辑代码,但是在 Java 源文件中通过字符串拼接的方式生成动态 HTML 内容会导致代码维护困难、可读性差
- JSP 虽然规避了 Servlet 在生成 HTML 内容方面的劣势,但是在 HTML 中混入大量、复杂的业务逻辑同样也是不可取的
通过 MVC 双剑合璧
既然 JSP 和 Servlet 都有自身的适用环境,那么能否扬长避短,让它们发挥各自的优势呢?答案是肯定的——MVC(Model-View-Controller)模式非常适合解决这一问题。
MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller):
- Controller——负责转发请求,对请求进行处理
- View——负责界面显示
- Model——业务功能编写(例如算法实现)、数据库设计以及数据存取操作实现
在 JSP/Servlet 开发的软件系统中,这三个部分的描述如下所示:
- Web 浏览器发送 HTTP 请求到服务端,被 Controller(Servlet) 获取并进行处理(例如参数解析、请求转发)
- Controller(Servlet) 调用核心业务逻辑——Model部分,获得结果
- Controller(Servlet) 将逻辑处理结果交给 View(JSP),动态输出 HTML 内容
- 动态生成的 HTML 内容返回到浏览器显示
MVC 模式在 Web 开发中的好处是非常明显,它规避了 JSP 与 Servlet 各自的短板,Servlet 只负责业务逻辑而不会通过 out.append() 动态生成 HTML 代码;JSP 中也不会充斥着大量的业务代码。这大大提高了代码的可读性和可维护性。
10. Tomcat 和 Servlet 的联系
Tomcat 是 Web 应用服务器,是一个 Servlet/JSP 容器。Tomcat 作为 Servlet 容器,负责处理客户请求,把请求传送给 Servlet,并将 Servlet 的响应传送回给客户。而 Servlet 是一种运行在支持 Java 语言的服务器上的组件。Servlet 最常见的用途是扩展 Java Web 服务器功能,提供非常安全的,可移植的,易于使用的 CGI 替代品。
① Tomcat 将 HTTP 请求文本接收并解析,然后封装成 HttpServletRequest 类型的 request 对象,所有的 HTTP 头数据读可以通过 request 对象调用对应的方法查询到。
② Tomcat 同时会要响应的信息封装为 HttpServletResponse 类型的 response 对象,通过设置 response 属性就可以控制要输出到浏览器的内容,然后将 response 交给 tomcat,Tomcat 就会将其变成响应文本的格式发送给浏览器。
Java Servlet API 是 Servlet 容器(tomcat) 和 servlet 之间的接口,它定义了 serlvet 的各种方法,还定义了 Servlet 容器传送给 Servlet 的对象类,其中最重要的就是 ServletRequest 和 ServletResponse。所以说我们在编写 servlet 时,需要实现 Servlet 接口,按照其规范进行操作。
11. cookie 和 session
什么是 cookie?
Cookie 是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现 Session 的一种方式。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。Cookie 使基于无状态的 HTTP 协议记录稳定的状态信息成为了可能。
什么是 session?
Session 代表着服务器和客户端一次会话的过程。Session 对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当客户端关闭会话,或者 Session 超时失效时会话结束。
二者区别
区别 | cookie | session |
---|---|---|
作用范围 | 保存在客户端(浏览器) | 保存在服务器端 |
存取方式 | 只能保存 ASCII | 可以存任意数据类型,一般情况下我们可以在 Session 中保持一些常用变量信息,比如说 UserId 等 |
有效期 | 可设置为长时间保持,比如我们经常使用的默认登录功能 | 一般失效时间较短,客户端关闭或者 Session 超时都会失效 |
隐私策略 | 存储在客户端,比较容易遭到不法获取 | 存储在服务端,安全性相对 Cookie 要好一些 |
存储大小 | 单个 Cookie 保存的数据不能超过 4K | 可存储数据远高于 Cookie |
为什么需要 cookie 和 session,他们有什么关联?
说起来为什么需要 Cookie ,这就需要从浏览器开始说起,我们都知道浏览器是没有状态的(HTTP 协议无状态),这意味着浏览器并不知道是张三还是李四在和服务端打交道。这个时候就需要有一个机制来告诉服务端,本次操作用户是否登录,是哪个用户在执行的操作,那这套机制的实现就需要 Cookie 和 Session 的配合。
既然服务端是根据 Cookie 中的信息判断用户是否登录,那么如果浏览器中禁止了 Cookie,如何保障整个机制的正常运转。
第一种方案,每次请求中都携带一个 SessionID 的参数,也可以 Post 的方式提交,也可以在请求的地址后面拼接 xxx?SessionID=123456...
。
第二种方案,Token 机制。Token 机制多用于 App 客户端和服务器交互的模式,也可以用于 Web 端做用户状态管理。
Token 的意思是“令牌”,是服务端生成的一串字符串,作为客户端进行请求的一个标识。Token 机制和 Cookie 和 Session 的使用机制比较类似。
当用户第一次登录后,服务器根据提交的用户信息生成一个 Token,响应时将 Token 返回给客户端,以后客户端只需带上这个 Token 前来请求数据即可,无需再次登录验证。
如何考虑分布式 Session 问题?
在互联网公司为了可以支撑更大的流量,后端往往需要多台服务器共同来支撑前端用户请求,那如果用户在 A 服务器登录了,第二次请求跑到服务 B 就会出现登录失效问题。
分布式 Session 一般会有以下几种解决方案:
- Nginx ip_hash 策略,服务端使用 Nginx 代理,每个请求按访问 IP 的 hash 分配,这样来自同一 IP 固定访问一个后台服务器,避免了在服务器 A 创建 Session,第二次分发到服务器 B 的现象。
- Session 复制,任何一个服务器上的 Session 发生改变(增删改),该节点会把这个 Session 的所有内容序列化,然后广播给所有其它节点。
- 共享 Session,服务端无状态话,将用户的 Session 等信息使用缓存中间件来统一管理,保障分发到每一个服务器的响应结果都一致。
12. JavaEE 中的三层结构和 MVC
做企业应用开发时,经常采用三层架构分层:表示层、业务层、持久层。
表示层:负责接收用户请求、转发请求、显示数据等。
业务层:负责组织业务逻辑。
持久层:负责持久化业务对象。
这三个分层,每一层都有不同的模式,就是架构模式。表示层最常用的架构模式就是 MVC。
MVC 是客户端的一种设计模式,所以他天然就不考虑数据如何存储的问题。作为客户端,只需要解决用户界面、交互和业务逻辑就好了。在 MVC 模式中,View 负责的是用户界面,Controller 负责交互,Model 负责业务逻辑。至于数据如何存储和读取,当然是由 Model 调用服务端的接口来完成。
在三层架构中,并没有客户端/服务端的概念,所以表示层、业务层的任务其实和 MVC 没什么区别,而持久层在 MVC 里面是没有的。
总结:MVC = 表示层 + 业务层,但不包括持久层。
13. RESTful 架构
什么是REST?
REST 是所有 Web 应用都应该遵守的架构设计指导原则。 面向资源是 REST 最明显的特征,对于同一个资源的一组不同的操作。对于每个资源只能执行一组有限的操作。(7个HTTP方法:GET/POST/PUT/DELETE/PATCH/HEAD/OPTIONS)
常用操作
HTTP方法 | 功能 |
---|---|
GET | select,从服务器取出资源(一项或多项)。 |
POST | create,在服务器新建一个资源。 |
PUT | update,在服务器更新资源(客户端提供改变后的完整资源)。 |
DELETE | delete,从服务器删除资源。 |