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

  1. Tomcat会为每个web应用创建一个ServletContext对象(创建和销毁与服务器启动和关闭对应)
  2. 作用:整个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.查看文件、源码

  1. 本质
    我们在本地这个目录里面能找到被编译成的.java和.class

    C:\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被包装了太多东西了。

  2. 对象
    继续看源码就能看到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                      //响应
    

    这啥,先不着急,接着往下看

  3. 预处理
    依旧是看源码,我们可以看到在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;
    

    认真看一下就能发现,这不就是一个类似于构造函数得到东西嘛,而且正好是对上面那些对象的初始化,那么一切就清晰了

  4. 内置对象
    传说中的九大内置对象已经开始明朗了

    • 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作用

  1. Web服务器的作用是接收客户端的请求,给客户端作出响应。
  2. 但是服务器不止静态资源,所以客户端访问的是动态资源,Web服务器不可能直接把它响应回去(比如JSP),因为浏览器只认识静态资源。
  3. 所以对于JavaWeb程序而言,还需要JSP/Servlet容器,其基本功能就是把动态资源转换成静态资源。
  4. Tomcat做到了这一点

3.Tomcat架构

对于他的架构,我们在前面的内容中基本已经说完了,这里再来复习一下
首先
在这里插入图片描述
各个文件夹的作用

bin:——启动脚本文件:startup.bat ——关闭脚本文件:shutdown.bat
conf:tomcat配置(如果碰到乱码问题可以在里面的logging.properties配置)
lib:依赖的jar包
logs:日志
webapps:存放网站内容

其次我们在web.xml里找到了两个默认的Servlet及其映射
在server.xml里找到了基础配置,其中

  1. <Server>代表服务器
  2. 下面有一个<Service>代表服务
  3. 下面有<Connector>和<Engine>,Connector作用就是监听端口,Engine作用是处理业务
    在这里插入图片描述

总结

讲到这也就差不多了,如果还想了解其他这方面的东西,就需要去拜读其他大佬的博客了
文章参考:
Servlet基础
深究Servlet
Jsp
Tomcat

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值