一、Servlet 基础认知
- Servlet 是 JavaWeb 三大核心组件之一,另外两个为 Filter(过滤器)、Listener(观察者模式),是 JavaWeb 学习的基础组件,需完全掌握。
- Servlet 即 Server Let,核心作用是处理用户请求,客户端发起请求后,由 Tomcat 匹配对应的 Servlet 进行处理,如登录请求由登录 Servlet 处理。
- Servlet 是运行在 Web 服务器中的小型 Java 程序,通常基于 HTTP 协议接收和响应 Web 客户端请求,需开发者自行编写,且必须实现 javax.servlet.Servlet 接口,同时在 web.xml 中部署,否则 Tomcat 无法识别。
二、Servlet 接口核心方法
- void init (ServletConfig servletConfig):Tomcat 创建 Servlet 实例后立即调用,仅调用一次,用于 Servlet 的初始化工作,需在方法中编写初始化代码。
- void service (ServletRequest request, ServletResponse response):Servlet 实例每次处理请求时都会调用,是处理请求的核心方法。
- void destroy ():Tomcat 销毁 Servlet 实例前调用,销毁本质是将 Servlet 从缓存池中移除,通常仅 Tomcat 关闭时触发该方法。
- ServletConfig getServletConfig ():返回对应 web.xml 中当前 Servlet 实例配置信息的 ServletConfig 对象,需在 init () 方法中保存参数后再返回,无法自行创建 ServletConfig 对象。
- String getServletInfo ():仅返回说明当前 Servlet 的字符串,实际开发中基本无使用价值。
三、第一个 Servlet 的创建步骤
步骤 1:编写 Servlet 实现类
创建 Java 类实现 javax.servlet.Servlet 接口,并重写接口中的所有方法,包结构与类名需明确,如 cn.tx.servlet.Servlet1。
步骤 2:配置 Servlet 访问路径
在 web.xml 文件中进行配置,包含<servlet>和<servlet-mapping>两个核心标签:
- <servlet>标签中,<servlet-name>定义 Servlet 名称,<servlet-class>指定 Servlet 实现类的全类名。
- <servlet-mapping>标签中,<servlet-name>与上述标签中的名称一致,<url-pattern>定义 Servlet 的访问路径。
四、JavaWeb 请求响应流程
- Tomcat 接收到客户端请求(如http://localhost:8080/servlet-demo1/hello)后,先识别 web 服务器地址、端口号、web 项目部署名称和请求路径。
- 根据项目部署名称找到对应 web 项目的 web.xml 文件。
- 通过请求路径匹配 web.xml 中<servlet-mapping>里的<url-pattern>。
- 根据匹配到的<url-pattern>找到对应的<servlet-name>,再通过该名称找到<servlet>标签中的<servlet-class>,获取 Servlet 类名。
- Tomcat 检查内存中是否存在该 Servlet 实例:存在则直接调用其 service () 方法;不存在则通过反射创建实例,存入 Servlet 池,再调用 service () 方法处理请求。
五、Servlet 的生命周期
- 初始化:Tomcat 创建 Servlet 实例后,立即调用 init () 方法完成初始化,该方法为生命周期方法,仅执行一次。
- 处理请求:每次客户端发起请求,Tomcat 都会调用 Servlet 实例的 service () 方法,该方法为生命周期方法,可多次执行。
- 销毁:Tomcat 关闭时,先调用 destroy () 方法,再销毁 Servlet 实例,该方法为生命周期方法,仅执行一次。
- Servlet 实例默认在浏览器第一次调用时创建,可通过配置修改创建时机;Servlet 的实例和方法均由 Tomcat 管理,开发者仅需编写实现类并部署。
- 自定义添加到 Servlet 中的方法,Tomcat 不会主动调用,可通过生命周期方法调用自定义方法。
六、HttpServlet 相关知识点
- HttpServlet 是专门处理 HTTP 请求的 Servlet,继承自 GenericServlet,而 GenericServlet 是 Servlet 接口的子类,实际开发中可直接继承 HttpServlet 编写 Servlet,无需实现原生 Servlet 接口。
- HTTP 请求方法包含 GET、POST、PUT、DELETE 等,常用的为 GET(通过请求 URI 获取资源)和 POST(用于添加新内容)。
- 创建 HttpServlet 的两种方法
- 方法 1:手动创建 Java 类继承 HttpServlet,再在 web.xml 中配置<servlet>和<servlet-mapping>标签,指定名称、全类名和访问路径。
- 方法 2:通过 IDEA 直接创建 Servlet,自动生成注解 @WebServlet,该注解可指定 Servlet 名称(name)和访问路径(urlPatterns),使用注解后无需在 web.xml 中配置。
- Servlet 创建时机的配置:如需 Tomcat 启动时即创建 Servlet,而非第一次访问时,可在 web.xml 的<servlet>标签中添加<load-on-startup>子元素。
- 元素值为 0 或大于 0 时,Tomcat 启动时加载该 Servlet。
- 元素值为序号,Tomcat 会按序号从小到大的顺序创建多个 Servlet 实例。
- 配置后 Tomcat 启动时仅创建 Servlet 实例并调用 init () 方法,不会处理请求。
七、ServletConfig
- ServletConfig 对象对应 web.xml 中<servlet>元素的配置信息,无法自行创建,Tomcat 调用 init () 方法时会传递该对象作为参数,可在 init () 方法中直接使用。
- 可在 web.xml 的<servlet>标签中添加<init-param>子元素,配置 Servlet 的初始化参数,每个<init-param>包含<param-name>(参数名)和<param-value>(参数值),可配置多个。
- ServletConfig 的核心方法
- String getInitParameter (String paramName):根据参数名获取对应的初始化参数值。
- Enumeration<String> getInitParameterNames ():返回所有初始化参数的名称,可通过遍历获取所有参数名和对应值。
- String getServletName ():获取当前 Servlet 在 web.xml 中配置的名称。
八、Servlet 路径映射
- Url-Pattern 的三种配置方式
- 完全路径匹配:以 / 开头,如 /aaa、/aaa/bbb。
- 目录匹配:以 / 开头且以结尾,如 /aaa/、/*。
- 扩展名匹配:不能以 / 开头,以开头加扩展名,如.do、*.action。
- 路径匹配优先级:完全路径匹配 > 目录匹配 > 扩展名匹配,禁止配置 /* .do 这类错误格式。
- 匹配规则示例
- 访问 /abc/a.html,/abc/(目录匹配)比 /(目录匹配)范围更精确,由对应 Servlet 处理。
- 访问 /abc,完全路径匹配 /abc 优先于目录匹配 /abc/*。
- 访问 /abc/a.do,目录匹配 /abc/优先于扩展名匹配.do。
- 访问 /a.do 或 /xxx/yyy/a.do,目录匹配 /优先于扩展名匹配.do。
九、相对路径和绝对路径
- Java 中本质仅能通过绝对路径寻找资源,相对路径是 API 底层构建绝对路径后的便利方法。
- 相对路径:根据当前资源路径与目标资源路径的相对位置关系,通过.(当前目录)和..(上一级目录)访问目标资源,编写规则随当前路径变化而变化。
- 绝对路径:指目录下的绝对位置,可直接到达目标位置,分两种类型
- 跨网站绝对路径:带有协议,如http://localhost/day5/hello。
- 同站点绝对路径:以 / 开始,如 /day5/hello。
- 服务器端与客户端对 / 的解析区别
- 客户端访问路径:/day5/hello(需包含项目部署名称)。
- 服务器内部路径:/hello(无需项目部署名称,多用于服务器跳转、页面包含)。
十、ServletContext
- ServletContext 基础特性
- 是全局的信息储存空间,服务器启动时创建,服务器关闭时释放,所有用户共用一个。
- WEB 容器为每个 WEB 应用创建一个对应的 ServletContext 对象,代表当前 web 应用。
- 同一个 WEB 应用中的所有 Servlet 共享一个 ServletContext 对象,可通过该对象实现 Servlet 间通讯,也被称为 context 域对象。
- 仅适合存放所有用户需要共享、线程安全、必要且重要的信息,节省空间并提高效率。
- ServletContext 核心 API
- Object getAttribute (String name):根据属性名获取 ServletContext 中存储的属性值,无对应属性则返回 null。
- String getContextPath ():返回当前 web 应用的上下文路径。
- String getInitParameter (String name):获取 web 应用的全局初始化参数值,无对应参数则返回 null。
- String getRealPath (String path):根据虚拟路径返回资源的真实绝对路径。
- void setAttribute (String name, Object object):将对象以指定属性名绑定到 ServletContext 中,实现数据共享。
- InputStream getResourceAsStream (String path):根据路径返回资源的输入流对象。
- InputStream getResourceAsStream (String path):获取指定路径资源的输入流。
- ServletContext 的常见使用场景
- 获取 WEB 应用全局初始化参数:在 web.xml 中通过<context-param>配置全局参数,包含<param-name>和<param-value>,通过 ServletContext 的 getInitParameter () 方法获取。
- 实现 Servlet 间数据共享:通过 setAttribute () 存储数据,通过 getAttribute () 获取数据,如实现站点访问次数统计功能。
- 读取资源文件的三种方法
- 通过 getRealPath ():先获取资源的真实绝对路径,再通过 FileInputStream 读取文件。
- 通过 getResourceAsStream ():直接传入资源虚拟路径(/ 代表项目根目录),获取输入流读取文件,适合读取 WEB-INF 下的资源。
- 通过类加载器:getClass ().getClassLoader ().getResourceAsStream (),无需依赖 ServletContext,可读取 classpath 下的资源,无需指定 / WEB-INF/classes。
十一、Servlet 核心面试考点
- 单例的 Servlet(单例多线程)
- Servlet 是单例的,由 Tomcat 管理,仅创建一个实例,与手动编写的单例模式实现方式不同。
- 单个 Servlet 实例需同时处理多个客户端的请求,属于单例多线程模式。
- Servlet 是线程不安全的,解决方式为:不在 Servlet 中定义属性,或不定义可存储数据的属性;若使用同步机制保证线程安全,会降低执行效率。
- Servlet 的生命周期(核心回答点)
- 初始化:Tomcat 创建 Servlet 实例后,调用 init () 方法完成初始化,仅执行一次。
- 处理请求:每次客户端发起请求,调用 service () 方法处理,可多次执行。
- 销毁:Tomcat 关闭时,调用 destroy () 方法终止 Servlet,仅执行一次。
- 回收:最终由 JVM 的垃圾回收器对 Servlet 实例进行垃圾回收。