Java Web Servlet 快速入门

用一个小例子来快速入门 Java Web 开发的灵魂 Servlet 。


什么是 Servlet

Servlt 简称是运行在服务端的小程序,所谓的 Servlet 其实就是一套规范(接口),而遵循这套规范(实现 Servlt 接口)所建立的 Java 类就能依赖于 HTTP 服务器(如 Tomcat)运行,相应的 Servlt 接口方法由服务器进行调用,而不用编写 main 方法进行独立运行。

Servlt 接口定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package javax.servlet;

import java.io.IOException;

public interface Servlet {
void init(ServletConfig var1) throws ServletException;

ServletConfig getServletConfig();

void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

String getServletInfo();

void destroy();
}

只要实现了 Servlt 接口就是一个最简单的 Servlt :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class ServletImpl implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("ServletImpl.init");
}

@Override
public ServletConfig getServletConfig() {
System.out.println("ServletImpl.getServletConfig");
return null;
}

@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("hello world");
}

@Override
public String getServletInfo() {
System.out.println("ServletImpl.getServletInfo");
return null;
}

@Override
public void destroy() {
System.out.println("ServletImpl.destroy");
}
}

实现完 Servlt 接口需要将其注册到 web.xml 中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">

<servlet>
<servlet-name>ServletImpl</servlet-name>
<servlet-class>com.peterxx.java.servlet.ServletImpl</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>ServletImpl</servlet-name>
<url-pattern>/api</url-pattern>
</servlet-mapping>

</web-app>

至此,一个能够响应浏览器请求的 Servlt 已经完成。


Servlet 的执行流程

从一个完整请求来看看 Servlet 是如何被 HTTP 服务器执行的:

  1. 浏览器发起一个 HTTP 请求:localhost:8080/api
    1. 通过 localhost 定位到本地机器。
    2. 通过 8080 端口定位到 Tomcat 服务。
  2. Tomcat 接收到请求 localhost:8080/api 后,在 web.xml 文件中查找 <servlet-mapping> 是否有 <url-pattern>/api</url-pattern> 配置
    1. 如果有则找到对应的 <servlet-name> ServletImpl 。
    2. 没有返回 404。
  3. 根据上一步找到的 <servlet-name> ServletImpl 去匹配 <servlet> ,获取到对应的 <servlet-class> com.peterxx.java.servlet.ServletImpl ,再去 Servlet 容器中查找是否已经有该类实例
    1. 如果有直接使用,调用 service 方法。
    2. 没有则通过反射生成一个 ServletImpl 实例,先调用 init 方法再调用 service 方法。
  4. 将经过 service 方法处理的结果返回给浏览器

注意,这是 Servlet 执行流程的大致分析,事实上在第 3 步,调用 service 方法之前,Tomcat 会将 HTTP 请求解析成 request 对象再调用 service 方法;而在第 4 步,Tomcat 会将 service 方法返回的 response 对象转换成 HTTP 响应返回给浏览器。


Servlet 的生命周期

要分析 Servlet 的生命周期就要回到最开始的 Servlt 接口定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package javax.servlet;

import java.io.IOException;

public interface Servlet {
void init(ServletConfig var1) throws ServletException;

ServletConfig getServletConfig();

void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

String getServletInfo();

void destroy();
}

分析其中最为核心的三个方法:

  • init :Servlet 的初始化方法,Servlet 的生命周期钩子函数。当 Servlet 被第一次请求的时候,会由 Servlet 容器(通常是 HTTP 服务器,如 Tomcat)负责创建相应的 Servlet 实例,并调用该方法,后续再去使用创建好的 Servlet 实例不会再去调用 init 方法。
  • service :Servlet 处理请求的核心方法,每次请求 Servlet 都会被调用。
  • destroy :同 init 方法,destroy 也是 Servlet 的生命周期钩子函数。当 Servlet 被销毁的时候,Servlet 容器会调用该方法。通常会在服务器被关闭的时候销毁 Servlet 。

注意,每个写好的 Servlet 实现类由于处理请求的逻辑都是一样,所以每个实现类只会被 Servlet 容器创建一个实例( Servlet 是单例),重复使用。而 Servlet 的创建时机可以在 web.xml 里面进行配置:通过 <load-on-startup>配置值</load-on-startup> 进行修改,当配置值为负数(默认)则是当 Servlet 被第一次访问时创建;配置值为 0 或正数,则是在服务器启动时创建。

以上三个核心方法贯穿了 Servlet 的生命周期。 initdestroy 只会在被创建和销毁的时候调用一次,而 service 则会根据 Servlet 被请求的次数调用多次。

另外两个方法 getServletConfig & getServletInfo 可以做简单了解:

  • getServletConfig:获取 ServletConfig 对象,也就是 Servlet 的配置对象。
  • getServletInfo:获取 Servlet 的一些信息。 Servlet 版本,作者等,通常不会去实现该方法。

Servlet 3.0 的注解配置

每次实现完新的 Servlet 都需要到 web.xml 中添加 <servlet></servlet> 和修改 <servlet-mapping></servlet-mapping> ,很不方便。于是从 Servlet 3.0 ( Java EE 6 开始)开始直接通过注解进行配置,而不再需要 web.xml 文件。

修改我们的 ServletImpl 类,添加 @WebServlet 注解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@WebServlet(urlPatterns = "/api")
public class ServletImpl implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("ServletImpl.init");
}

@Override
public ServletConfig getServletConfig() {
System.out.println("ServletImpl.getServletConfig");
return null;
}

@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("hello world");
}

@Override
public String getServletInfo() {
System.out.println("ServletImpl.getServletInfo");
return null;
}

@Override
public void destroy() {
System.out.println("ServletImpl.destroy");
}
}

同时删除 web.xml 中的相关配置,运行发现效果和使用 web.xml 是一样的。

强类型语言 & 弱类型语言、动态语言 & 静态语言 SQL中的关键字的执行顺序

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×