servlet基础原理

1、servlet的体系架构


serlvet 的这套东西大概如下图,这些是基本的东西 。HttpSerlvet,HttpServletRequest 这些扩展的东西就没有放到这里了。

tomcat 架构中 servlet的类关系图

这些接口是干什么用的呢:

  • ServletRequest:规定了获取请求相关信息的接口,由容器实现。
  • ServletResponse : 由容器实现,提供了相关响应请求的接口。
  • ServletConfig:由web容器实现 提供了相关servlet配置信息的接口
  • ServletContext: web容器会对每个web应用创建一个环境,所以的组件,jsp 等都运行在同一个环境中,ServletContext就是提供了这个环境访问途径。由容器实现
  • servlet: 由业务实现 提供了 init() service() destroy() 给容器对servlet进行初始化和 调用服务 和销毁 的时候调用。

相关Servlet的接口说明可以看

http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/

2、serlvet和web容器协同工作流程


工作流程大致如下:

  1. 初始化环境: 根据context.xml的配置 进行初始化 (这个时候就会实例化一个ServletContext)
  2. 加载web.xml 根据web.xml描述初始化相关组件
  3. 有请求到达容器的时候 容器处理请求 实例一个 servletRequest 和 servletResponse
  4. 调用servlet的service方法 将servletRequest 和 servletResponse 实例传给了 servlet
  5. servlet 处理完成相关业务逻辑 将结果写入servletResponse 中

这里写图片描述

下面是模拟这个工作过程的测试代码 (摘取重要代码)

处理请求的过程

...
private void processRequest(ServerSocket serverSocket) throws IOException {
        System.out.println("等待请求");
        Socket socket=serverSocket.accept();
        System.out.println("接受到请求:"+socket.getRemoteSocketAddress().toString());
        InputStream in=socket.getInputStream();
        BaseRequest request = new BaseRequest(in);
        OutputStream out = socket.getOutputStream();
        BaseResponse response = new BaseResponse(out);
        ServletProcessor.processServletRequest(request, response);
        socket.close();
    }
...
...
public static void processServletRequest(BaseRequest request, BaseResponse response) {
        String uri = request.getUri();
        String servletName ="com.saoyor.controller.HelloController";
        Servlet servlet = loadServlet(servletName);
        servlet.service(request, response);
    }
...

处理请求数据

...
public BaseRequest(InputStream in) {
        this.inputStream = in;
        prepareContent();
        parseAndSetUri();
    }
private void prepareContent() {

        byte[] buffer = new byte[2048];
        int i = -1;

        try {
            i = inputStream.read(buffer);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println(i);
        for (int k = 0; k < i; k++) {
            requestContentBuffer.append((char) buffer[k]);
        }
        System.out.println(requestContentBuffer.toString());

    }
private void parseAndSetUri() {
        String requestString = requestContentBuffer.toString();
        int index1 = requestString.indexOf(' ');
        int index2 = -1;
        if (index1 != -1) {
            index2 = requestString.indexOf(' ', index1 + 1);
        }
        this.uri = (index2 > index1) ? requestString.substring(index1 + 1,
                index2) : null;

    }
public String getUri() {
        return this.uri;
    }
...

3、servlet的生命周期

1、 servlet的创建
有两种创建方式 一种是配置容器启动的时候就创建,另外一种是 容器请求的时候发现没有这个servlet就会根据web.xml的表述创建一个。
servlet被创建的时候会调用 一次init()方法 并且会传人 ServletConfig对象

2、servlet处理请求
servlet对象一旦被创建就会一直存在 直到被销毁了。所以的对这个servlet请求都会调用同一个对象的service方法。

3、servlet的销毁
servlet只有在容器关闭 或者被移除的时候才会销毁 销毁的时候会调用servlet的destroy()方法 可以处理程序在被销毁前需要处理的事情

如果下图

这里写图片描述

因为每个请求使用同一个的servlet,这样就牵扯到了线程的安全问题,这里有一些开发建议

  • 用方法的局部变量保存请求中的专有数据。对方法中定义的局部变量,进入方法的每个线程都有自己的一份方法变量拷贝。任何线程都不会修改其他线程的局部变量。

  • 只用Servlet的成员变量来存放那些不会改变的数据。有些数据在Servlet生命周期中不发生任何变化,通常是在初始时确定的,这些数据可以使用成员变量保存,如数据库连接名称、其他资源的路径等。

  • 对可能被请求修改的成员变量同步。有时数据成员变量或者环境属性可能被请求修改。当访问这些数据时应该对它们同步,以避免多个线程同时修改这些数据。

  • 如果Servlet访问外部资源,那么需要同步访问这些资源。例如,假设Servlet要从文件中读写数据。当一个线程读写一个文件时,其他线程也
    可能正在读写这个文件。文件访问本身不是线程安全的,所以必须编写同步访问这些资源的代码。

在编写线程安全的Servlet时,下面两种方法是不应该使用的:

  • 在Servlet API中提供了一个SingleThreadModel接口,实现这个接口的Servlet在被多个客户请求时一个时刻只有一个线程运行。这个接口已被标记不推荐使用。

  • 对doGet()或doPost()方法同步。如果必须在Servlet中使用同步代码,应尽量在最小的代码块范围上进行同步。同步代码越小,Servlet执行得才越好。

4、web.xml

web.xml 是用来配置业务组件的,容器启动的时候会加载这份web.xml去指导容器初始化相关组件。

下面是一份用来测试的web.xml

<web-app>

    <display-name>Archetype Created Web Application</display-name>

    <description>用了测试servlet 相关功能</description>


    <!-- 过滤器配置  过滤器是会运行在请求之前 和 响应之后的-->
    <!-- 过滤器在 文档中的位置一定要在servlet的配置之前-->
    <filter>
        <filter-name>requestfilter</filter-name>
        <filter-class>com.soyor.servlet.filter.RequestFilter</filter-class>
    </filter>

    <!-- 配置过滤哪些 servlet -->
    <filter-mapping>
        <filter-name>requestfilter</filter-name>
        <servlet-name>Hello</servlet-name>
    </filter-mapping>
    <!-- 过滤器同样可以对请求路径起作用-->
    <filter-mapping>
        <filter-name>requestfilter</filter-name>
        <url-pattern>/test</url-pattern>
    </filter-mapping>


    <!-- 定义servlet-->
    <servlet>
        <servlet-name>Hello</servlet-name>
        <servlet-class>com.soyor.servlet.HelloController</servlet-class>
        <!-- servlet的初始化变量 -->
        <init-param>
            <param-name>abc</param-name>
            <param-value>123</param-value>
        </init-param>
        <!-- servlet的加载的优先级  <0 的时候 启动不加载-->
        <load-on-startup>2</load-on-startup>

    </servlet>

    <servlet>
        <servlet-name>test</servlet-name>
        <servlet-class>com.soyor.servlet.TestController</servlet-class>
        <load-on-startup>3</load-on-startup>
    </servlet>


    <servlet-mapping>
        <servlet-name>Hello</servlet-name>
        <url-pattern>/Hello</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>test</servlet-name>
        <url-pattern>/test</url-pattern>
    </servlet-mapping>


</web-app>

web.xml 相关元素说明

元素说明
icon元素指出IDE和GUI工具用来表示Web应用的一个和两个图像文件的位置。
display-name元素提供GUI工具可能会用来标记这个特定的Web应用的一个名称。
description元素给出与此有关的说明性文本。
context-param元素声明应用范围内的初始化参数。
filter过滤器元素将一个名字与一个实现javax.servlet.Filter接口的类相关联。
filter-mapping一旦命名了一个过滤器,就要利用filter-mapping元素把它与一个或多个servlet或JSP页面相关联。
listenerservlet API的版本2.3增加了对事件监听程序的支持,事件监听程序在建立、修改和删除会话或servlet环境时得到通知。Listener元素指出事件监听程序类。
servlet在向servlet或JSP页面制定初始化参数或定制URL时,必须首先命名servlet或JSP页面。Servlet元素就是用来完成此项任务的。
servlet-mapping服务器一般为servlet提供一个缺省的URL:http://host/webAppPrefix/servlet/ServletName。但是,常常会更改这个URL,以便servlet可以访问初始化参数或更容易地处理相对URL。在更改缺省URL时,使用servlet-mapping元素。
session-config如果某个会话在一定时间内未被访问,服务器可以抛弃它以节省内存。可通过使用HttpSession的setMaxInactiveInterval方法 明确设置单个会话对象的超时值,或者可利用session-config元素制定缺省超时值。
mime-mapping如果Web应用具有想到特殊的文件,希望能保证给他们分配特定的MIME类型,则mime-mapping元素提供这种保证。
welcom-file-list元素指示服务器在收到引用一个目录名而不是文件名的URL时,使用哪个文件。
error-page元素使得在返回特定HTTP状态代码时,或者特定类型的异常被抛出时,能够制定将要显示的页面。
taglib元素对标记库描述符文件(Tag Libraryu Descriptor file)指定别名。此功能使你能够更改TLD文件的位置,而不用编辑使用这些文件的JSP页面。
resource-env-ref元素声明与资源相关的一个管理对象。
resource-ref元素声明一个资源工厂使用的外部资源。
security-constraint元素制定应该保护的URL。它与login-config元素联合使用
login-config用login-config元素来指定服务器应该怎样给试图访问受保护页面的用户授权。它与sercurity-constraint元素联合使用。
security-role元素给出安全角色的一个列表,这些角色将出现在servlet元素内的security-role-ref元素的role-name子元素中。分别地声明角色可使高级IDE处理安全信息更为容易。
env-entry元素声明Web应用的环境项。
ejb-ref元素声明一个EJB的主目录的引用。
ejb-local-ref元素声明一个EJB的本地主目录的应用。\
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值