Javaweb(三)Servlet/Jsp原理篇
前言
本章开始涉及javaweb主体内容,主要讲解Servlet、Jsp以及Tomcat在客户端与服务端的交互过程中各自有什么用
如果还有新手村玩家(比如我 )没有看前两张基础篇,建议先去学一下基础知识哦
Javaweb(一)基础知识篇
JavaWeb(二)框架搭建篇
这里先放一张整体架构图
一、Servlet
1.什么是servlet
服务器三个主要过程:1.接受请求 2.处理请求 3.响应请求
其中1和3是共性的功能,这个就交由tomcat来做了
由于处理请求的逻辑不同,那么就把这个过程出去出来,作为Servlet,交给程序员编写
随着互联网的发展,有一些逻辑也从servlet中抽取出来分为service层和Dao层
2.如何编写Servlet
首先去查看Servlet的源码
public interface Servlet {
//Tomcat(由web.xml解析反射创建Servlet之后)调用init(),传入ServletConfig
void init(ServletConfig var1) throws ServletException;
//Servlet配置 由web.xml解析,创建ServletConfig实例
ServletConfig getServletConfig();
//Http请求到了Tomcat之后,Tomcat通过解析把url、参数等都封装进了Request,并同时生成空Response
//由Servlet处理后的数据通过response.write()写入response的缓冲区,最后Tomcat拿到response,组装成http响应发给客户端
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
void destroy();
}
再去找实现了Servlet的抽象类GenericServlet
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
//得到ServletContext
public ServletContext getServletContext() {
ServletConfig sc = this.getServletConfig();
if (sc == null) {
throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
} else {
return sc.getServletContext();
}
}
//提升ServletConfig作用域
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public void init() throws ServletException {
}
public ServletConfig getServletConfig() {
return this.config;
}
//最重要的service还是没有实现
public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
}
继续看GenericServlet的子类HttpServlet
public abstract class HttpServlet extends GenericServlet {
//实现了各种请求方式
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {...}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {...}
protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {...}
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {...}
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {...}
protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {...}
//实现了service 完成了复杂的请求方式判断,并且调用了对应的函数
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {...}
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {... }
}
到此,基础源码就差不多看完了
也就是说Servlet是一个接口,我们需要写一个类继承一个实现了Servlet接口的抽象类
换句话说,我们实现了doGet和doPost就可以实现一个Servlet了
3.深究Servlet—ServletContext
- Tomcat会为每个web应用创建一个ServletContext对象(创建和销毁与服务器启动和关闭对应)
- 作用:整个Web应用的动态资源(Servlet/JSP)之间共享数据。例如在Aservlet中向ServletContex保存一个值(setAttribute()),然后在Bservlet中就可以获取这个值(getAttribute())。
另:这种装载共享数据的对象,在Javaweb中有四个,被叫作“域对象”:
- ServletContext域(Servlet间共享数据)
- Session域(一次会话间共享数据,也可以理解为多次请求间共享数据)
- Request域(同一次请求共享数据)
- Page域(JSP页面内共享数据)
它们都可以看做是map,都有getAttribute()/setAttribute()方法。
4.深究Servlet—Servlet映射器
浏览器发送的请求会先经过映射器,由映射规则配发给各个Servlet
我们继续扒源码,这次翻到tomcat的web.xml下,可以看到tomcat默认带了俩Servlet
也就是说
- 对于静态资源,Tomcat最后会交由DefaultServlet
- 对于Servlet ,Tomcat最后会交由 InvokerServlet
- 对于JSP,Tomcat最后会交由JspServlet
- 对于其他,Tomcat会交由我们自定义的Servlet来处理
另:如果某个Servlet的映射路径仅仅为一个正斜杠(/),那么这个Servlet就成为当前Web应用的缺省Servlet。凡是在web.xml文件中找不到匹配的元素的URL,它们的访问请求都将交给缺省Servlet处理。就像是Tomcat里面自带的DefaultServlet,当我们访问静态页面的时候,就是在访问他
5.深究Servlet—过滤器
过滤器Fileter是一个小型的web组件,它们通过拦截请求和响应,以便查看、提取或以某种方式操作客户端和服务器之间交换的数据,实现“过滤”的功能
继续翻源码,我们依旧可以在web.xml中找到拦截器及其映射
对于每个映射到的url,都会经过过滤器,也就是说我们一般会把共性的操作放到过滤器实现
6.深究Servlet—线程安全
会不会有人想到用线程锁(synchronized)?
很好,可是这样的话就会出现一个问题,对于高并发的情况,我们确实保证了数据的安全,但是对于每一个线程都会上锁,也就是说用户的请求需要排队一个一个进行处理,这好像并不是很合适吧。
持续更新…
二、Jsp
1.Jsp起因
早期的服务器端是用Java开发的,我们看到的html页面都是由前端写好,交给后端程序员,后端在Servlet中调用out.println("<h1>…</h1>")拼接数据和html语句,非常麻烦。但是同时期的PHP就很好了,他选择在html里面嵌入语言引入动态数据。于是sun公司就开发出了Jsp
2.Jsp是什么
JSP全称Java Server Page,就是在html里面嵌套Java代码,实现动态数据
3.Jsp处理流程
Web容器(Tomcat)接受到以.jsp为拓展名的url请求的访问时,会将他交给Jsp引擎处理(JspServlet),也就是我们上面提到过的Tomcat自带的默认映射。每个Jsp页面第一次被访问时,JspServlet都会把他翻译成一个Servlet程序(.java),接着再把这个程序编译成类文件(.class),然后再由Tomcat像调用普通Servlet那样执行程序。
4.查看文件、源码
-
本质
我们在本地这个目录里面能找到被编译成的.java和.classC:\Users\(用户名)\AppData\Local\JetBrains\IntelliJIdea2021.2\tomcat\(项目名)\work\Catalina\localhost\ROOT\org\apache\jsp
打开看源码
可以看到,被编译成的.java其实也是用out.write()写的html页面,也就是说程序帮我们做了“把html代码复制进Servlet并用out.write()输出”的操作。我们再去看index_jsp这个类的继承情况
HttpJspBase,我们再去翻他(强迫症将就一下吧,SuppressWarnings都没压住报错)
看到了什么?HttpServlet!我们的Servlet不也是继承的他嘛。也就是说Jsp本质上其实就是一个Servlet,只不过Jsp被包装了太多东西了。 -
对象
继续看源码就能看到Jsp里面有这些属性final javax.servlet.jsp.PageContext pageContext; //页面上下文 javax.servlet.http.HttpSession session = null; //session final javax.servlet.ServletContext application; //applicationContext final javax.servlet.ServletConfig config; //config javax.servlet.jsp.JspWriter out = null; //out final java.lang.Object page = this; //page:当前页 HttpServletRequest request //请求 HttpServletResponse response //响应
这啥,先不着急,接着往下看
-
预处理
依旧是看源码,我们可以看到在Jsp开始疯狂的out.write()之前有这么一段代码response.setContentType("text/html"); //设置响应页面类型(动态资源变成静态) pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true); _jspx_page_context = pageContext; application = pageContext.getServletContext(); //application=ServletContext config = pageContext.getServletConfig(); session = pageContext.getSession(); out = pageContext.getOut(); _jspx_out = out;
认真看一下就能发现,这不就是一个类似于构造函数得到东西嘛,而且正好是对上面那些对象的初始化,那么一切就清晰了
-
内置对象
传说中的九大内置对象已经开始明朗了- PageContext 【存东西】
- Request 【存东西】
- Response
- Session 【存东西】
- Application ——就是SerlvetContext 【存东西】
- config ——就是SerlvetConfig
- out
- page
- exception
那他们有什么区别呢
pageContext.setAttribute("name1","1"); //保存的数据只在一个页面中有效 request.setAttribute("name2","2"); //保存的数据只在一次请求中有效,请求转发会携带这个数据 session.setAttribute("name3","3"); //保存的数据只在一次会话中有效,从打开浏览器到关闭浏览器 application.setAttribute("name4","4"); //保存的数据只在服务器中有效,从打开服务器到关闭服务器
我们取属性的先后顺序是pageContext -> request -> session -> application(双亲委派机制)
三、Tomcat
有了上面两内容的学习,相信各位对 Tomcat已经有了初步的理解
1.Tomcat是什么
Tomcat是轻量级的服务器,也被称为Servlet/JSP容器。
2.Tomcat作用
- Web服务器的作用是接收客户端的请求,给客户端作出响应。
- 但是服务器不止静态资源,所以客户端访问的是动态资源,Web服务器不可能直接把它响应回去(比如JSP),因为浏览器只认识静态资源。
- 所以对于JavaWeb程序而言,还需要JSP/Servlet容器,其基本功能就是把动态资源转换成静态资源。
- Tomcat做到了这一点
3.Tomcat架构
对于他的架构,我们在前面的内容中基本已经说完了,这里再来复习一下
首先
各个文件夹的作用
bin:——启动脚本文件:startup.bat ——关闭脚本文件:shutdown.bat
conf:tomcat配置(如果碰到乱码问题可以在里面的logging.properties配置)
lib:依赖的jar包
logs:日志
webapps:存放网站内容
其次我们在web.xml里找到了两个默认的Servlet及其映射
在server.xml里找到了基础配置,其中
- <Server>代表服务器
- 下面有一个<Service>代表服务
- 下面有<Connector>和<Engine>,Connector作用就是监听端口,Engine作用是处理业务
总结
讲到这也就差不多了,如果还想了解其他这方面的东西,就需要去拜读其他大佬的博客了
文章参考:
Servlet基础
深究Servlet
Jsp
Tomcat