当前位置: 首页 > news >正文

Servlet开发与生命周期详解-2

一、在集成开发环境当中开发Servlet程序

1.集成开发工具很多,其中目前使用比较多的是:

  • IntelliJ IDEA(这个居多,IDEA在提示功能方面要强于Eclipse,也就是说IDEA使用起来比Eclipse更加智能,更好用。JetBrain公司开发的。收费的。)

  • Eclipse(这个少一些),Eclipse目前还是有团队使用,只不过处于减少的趋势,自己从事工作之后,可能会遇到。Eclipse是IBM团队开发的。Eclipse寓意是“日食”。“日食”表示将太阳吃掉。太阳是SUN。IBM团队开发Eclipse的寓意是吞并SUN公司,但是2009年的时候SUN公司被Oracle公司并购了。IBM并没有成功并购SUN公司。

2.使用IDEA集成开发工具开发Servlet

  • 第一步:New Project(我比较习惯先创建一个Empty Project【空工程】,然后在空工程下新建Module【模块】,这不是必须的,只是一种习惯,你可以直接新建非空的Project),这个Empty Project起名为:javaweb(不是必须的,只是一个名字而已。一般情况下新建的Project的名字最好和目录的名字一致。)

  • 第二步:新建模块(File --> new --> Module...)

    • 这里新建的是一个普通的JavaSE模块(这里先不要新建Java Enterprise模块)

    • 这个Module自动会被放在javaweb的project下面。

    • 这个Module起名:servlet01

  • 第三步:让Module变成JavaEE的模块。(让Module变成webapp的模块。符合webapp规范。符合Servlet规范的Module)

    • 在Module上点击右键:Add Framework Support...(添加框架支持)

    • 在弹出的窗口中,选择Web Application(选择的是webapp的支持)

    • 选择了这个webapp的支持之后,IDEA会自动给你生成一个符合Servlet规范的webpp目录结构。

    • 重点,需要注意的:在IDEA工具中根据Web Application模板生成的目录中有一个web目录,这个目录就代表webapp的根

  • 第四步(非必须):根据Web Application生成的资源中有index.jsp文件,这里我选择删除这个index.jsp文件。

  • 第五步:编写Servlet(StudentServlet)

    • class StudentServlet implements Servlet

    • 这个时候发现Servlet.class文件没有。怎么办?将CATALINA_HOME/lib/servlet-api.jar和jsp-api.jar添加到classpath当中(这里的classpath说的是IDEA的classpath)

      • File --> Project Structrue --> Modules --> + 加号 --> Add JARS....

    • 实现jakarta.servlet.Servlet接口中的5个方法。

  • 第六步:在Servlet当中的service方法中编写业务代码(我们这里连接数据库了。)

  • 第七步:在WEB-INF目录下新建了一个子目录:lib(这个目录名可不能随意,必须是全部小写的lib),并且将连接数据库的驱动jar包放到lib目录下。

  • 第八步:在web.xml文件中完成StudentServlet类的注册。(请求路径和Servlet之间对应起来)

    <?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_4_0.xsd"version="4.0"><!-- 定义一个 Servlet 配置 --><servlet><!-- 为 Servlet 定义一个名称,这个名称用于在后续的映射配置中引用该 Servlet --><servlet-name>studentServlet</servlet-name><!-- 指定 Servlet 类的全限定名,即包含包名的类名,服务器会根据这个类名来实例化 Servlet --><servlet-class>oop1.StudentServlet</servlet-class></servlet><!-- 定义 Servlet 的映射配置,将一个 URL 模式映射到之前定义的 Servlet 上 --><servlet-mapping><!-- 指定要映射的 Servlet 的名称,这个名称必须与上面 <servlet> 标签中定义的名称一致 --><servlet-name>studentServlet</servlet-name><!-- 定义一个 URL 模式,当客户端请求的 URL 匹配这个模式时,服务器会将请求转发给对应的 Servlet 进行处理 --><url-pattern>/servlet/student</url-pattern></servlet-mapping>
    </web-app>

    当客户端请求的 URL 为 /servlet/student 时,服务器会找到 oop1.StudentServlet 类的实例来处理该请求。

第九步:给一个html页面,在HTML页面中编写一个超链接,用户点击这个超链接,发送请求,Tomcat执行后台的StudentServlet。

  • student.html

  • 这个文件不能放到WEB-INF目录里面,只能放到WEB-INF目录外面。

  • student.html文件的内容

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>student page</title>
</head>
<body><!--这里的项目名是 /xmm ,无法动态获取,先写死--><a href="/xmm/servlet/student">student list</a>
</body>
</html>
  • 第十步:让IDEA工具去关联Tomcat服务器。关联的过程当中将webapp部署到Tomcat服务器当中。

    • IDEA工具右上角,绿色小锤子右边有一个:Add Configuration

    • 左上角加号,点击Tomcat Server --> local

    • 在弹出的界面中设置服务器Server的参数(基本上不用动)

    • 在当前窗口中有一个Deployment(点击这个用来部署webapp),继续点击加号,部署即可。

    • 修改 Application context为:/xmm

  • 第十一步:启动Tomcat服务器

    • 在右上角有绿色的箭头,或者绿色的小虫子,点击这个绿色的小虫子,可以采用debug的模式启动Tomcat服务器。

    • 我们开发中建议适用debug模式启动Tomcat

  • 第十二步:打开浏览器,在浏览器地址栏上输入:http://localhost:8080/xmm/student.html

3.tomcat配置的解释

⑴.通用设置

  • Name
    翻译:名称
    解释:给当前运行 / 调试配置设置一个自定义名称,方便区分不同配置。
  • Store as project file
    翻译:存储为项目文件
    解释:勾选后,该配置会保存为项目文件,便于团队共享或重复使用。

⑵.标签页

  • Server
    翻译:服务器
    解释:配置服务器相关参数,如端口、浏览器打开设置等。
  • Deployment
    翻译:部署
    解释:设置项目如何部署到服务器(如部署目录、war 包等)。
  • Logs
    翻译:日志
    解释:查看服务器日志相关设置或直接查看日志内容。
  • Code Coverage
    翻译:代码覆盖率
    解释:分析代码在运行时的执行覆盖情况(需额外工具支持)。
  • Startup/Connection
    翻译:启动 / 连接
    解释:配置服务器启动参数、连接超时等与启动和连接相关的设置。

⑶.Server 标签页内容

  • Application server
    翻译:应用服务器
    解释:下拉选择已配置的应用服务器(如 Tomcat),若未配置,需点击右侧 Configure 配置。
  • Open browser
    翻译:打开浏览器
    解释:设置服务器启动后是否自动打开浏览器。
    • After launch翻译:启动后;解释:勾选表示服务器启动后执行后续操作(如打开浏览器)。
    • with JavaScript debugger翻译:使用 JavaScript 调试器;解释:调试时启用 JavaScript 调试功能。
  • URL
    翻译:统一资源定位符
    解释:设置服务器启动后自动打开的网址(如项目访问地址)。
  • VM options
    翻译:虚拟机选项
    解释:填写 JVM 运行参数(如内存分配 -Xmx512m 等)。
  • On 'Update' action
    翻译:在 “更新” 操作时
    解释:选择对项目更新时服务器的响应动作。
    • Restart server翻译:重启服务器;解释:代码更新时重启服务器。
    • Show dialog翻译:显示对话框;解释:执行更新操作时弹出确认对话框。
  • JRE
    翻译:Java 运行时环境
    解释:选择项目运行所需的 JRE(Java Runtime Environment)。

⑷Tomcat Server Settings(Tomcat 服务器设置)

  • HTTP port
    翻译:HTTP 端口
    解释:设置 Tomcat 用于 HTTP 通信的端口(默认 8080)。
  • Deploy applications configured in Tomcat instance
    翻译:部署 Tomcat 实例中配置的应用
    解释:勾选后,会部署 Tomcat 自身配置的应用(而非通过 IDE 配置的应用)。
  • HTTPS port
    翻译:HTTPS 端口
    解释:设置 Tomcat 用于 HTTPS 通信的端口(需配置 SSL 证书)。
  • Preserve sessions across restarts and redeploys
    翻译:在重启和重新部署时保留会话
    解释:勾选后,服务器重启或重新部署时保留用户会话信息(如登录状态)。
  • AJP port
    翻译:AJP 端口
    解释:设置 Tomcat 用于 AJP(Apache JServ Protocol)协议的端口,用于与其他服务器通信。

二、Servlet对象的生命周期

1.什么是Servlet对象生命周期?

  • Servlet对象什么时候被创建。

  • Servlet对象什么时候被销毁。

  • Servlet对象创建了几个?

  • Servlet对象的生命周期表示:一个Servlet对象从出生在最后的死亡,整个过程是怎样的。

2.Servlet对象是由谁来维护的?

  • Servlet对象的创建,对象上方法的调用,对象最终的销毁,Javaweb程序员是无权干预的。

  • Servlet对象的生命周期是由Tomcat服务器(WEB Server)全权负责的。

  • Tomcat服务器通常我们又称为:WEB容器。(这个叫法你要知道【WEB Container】

  • WEB容器来管理Servlet对象的死活。

3.思考:我们自己new的Servlet对象受WEB容器的管理吗?

Web容器中的Map集合
  • 我们自己new的Servlet对象是不受WEB容器管理的。

  • WEB容器创建的Servlet对象,这些Servlet对象都会被放到一个集合当中(HashMap),只有放到这个HashMap集合中的Servlet才能够被WEB容器管理,自己new的Servlet对象不会被WEB容器管理。(自己new的Servlet对象不在容器当中)

  • web容器底层应该有一个HashMap这样的集合,在这个集合当中存储了Servlet对象和请求路径之间的关系

4.研究:服务器在启动的Servlet对象有没有被创建出来(默认情况下)?

  • 在Servlet中提供一个无参数的构造方法,启动服务器的时候看看构造方法是否执行。

  • 经过测试得出结论:默认情况下,服务器在启动的时候Servlet对象并不会被实例化。

  • 这个设计是合理的。用户没有发送请求之前,如果提前创建出来所有的Servlet对象,必然是耗费内存的,并且创建出来的Servlet如果一直没有用户访问,显然这个Servlet对象是一个废物,没必要先创建。

使用简单代码验证:

⑴创建新模块:

oop1包下的AServlet

package oop1;import jakarta.servlet.*;import java.io.IOException;public class AServlet implements Servlet {// 无参数构造方法public AServlet() {System.out.println("AServlet无参数构造方法执行了");}// 程序员手动提供Servlet类的有参数的构造方法,会怎么样?/*public AServlet(String s){}*/// init被翻译为初始化// init方法只执行一次// 在AServlet对象第一次被创建之后执行。// init方法通常是完成初始化操作的。// init方法在执行的时候AServlet对象已经被创建出来了。@Overridepublic void init(ServletConfig servletConfig) throws ServletException {System.out.println("AServlet's init method execute!");}// service方法:是处理用户请求的核心方法。// 只要用户发送一次请求,service方法必然会执行一次。// 发送100次请求,service方法则执行100次。@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {System.out.println("AServlet's service method execute!");}// destroy方法也是只执行一次。// Tomcat服务器在销毁AServlet对象之前会调用一次destroy方法// destroy方法在执行的时候,AServlet对象的内存还没有被销毁。即将被销毁。// destroy方法中可以编写销毁前的准备。// 比如说,服务器关闭的时候,AServlet对象开启了一些资源,这些资源可能是流,可能是数据库连接// 那么,关闭服务器的时候,要关闭这些流,关闭这些数据库连接,那么这些关闭资源的代码就可以写到destroy方法当中。@Overridepublic void destroy() {System.out.println("AServlet's destroy method execute!");}@Overridepublic ServletConfig getServletConfig() {return null;}@Overridepublic String getServletInfo() {return null;}
}

oop1包下的BServlet

package oop1;import jakarta.servlet.*;import java.io.IOException;public class BServlet implements Servlet {// 无参数构造方法public BServlet() {System.out.println("BServlet无参数构造方法执行了");}@Overridepublic void init(ServletConfig servletConfig) throws ServletException {}@Overridepublic ServletConfig getServletConfig() {return null;}@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {}@Overridepublic String getServletInfo() {return null;}@Overridepublic void destroy() {}
}

web.xml

<?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_4_0.xsd"version="4.0"><servlet><servlet-name>aservlet</servlet-name><servlet-class>oop1.AServlet</servlet-class></servlet><servlet-mapping><servlet-name>aservlet</servlet-name><url-pattern>/a</url-pattern></servlet-mapping><servlet><servlet-name>bservlet</servlet-name><servlet-class>oop1.BServlet</servlet-class></servlet><servlet-mapping><servlet-name>bservlet</servlet-name><url-pattern>/b</url-pattern></servlet-mapping>
</web-app>

中间忽略红字

 生命周期流程图

容器启动↓
创建 Servlet 实例 → 若失败 → 标记为不可用↓
调用 init(config) → 若抛出异常 → 销毁实例↓
等待请求 → 调用 service(req, res)↓
容器关闭/卸载应用↓
调用 destroy() → 清理资源↓
Servlet 实例被回收

5.怎么让服务器启动的时候创建Servlet对象呢?

  • 在servlet标签中添加<load-on-startup>子标签,在该子标签中填写整数,越小的整数优先级越高。

<servlet><servlet-name>aservlet</servlet-name><servlet-class>oop1.AServlet</servlet-class><load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping><servlet-name>aservlet</servlet-name><url-pattern>/a</url-pattern>
</servlet-mapping>

越小的整数优先级越高。

6.Servlet对象生命周期

  • 默认情况下服务器启动的时候AServlet对象并没有被实例化

  • 用户发送第一次请求的时候,控制台输出了以下内容:

AServlet无参数构造方法执行了
AServlet's init method execute!
AServlet's service method execute!

只要在网页上输入http://127.0.0.1:8080/lifecycle/a

就会显示

AServlet's service method execute!

  • 根据以上输出内容得出结论:

    • 用户在发送第一次请求的时候Servlet对象被实例化(AServlet的构造方法被执行了。并且执行的是无参数构造方法。)

    • AServlet对象被创建出来之后,Tomcat服务器马上调用了AServlet对象的init方法。(init方法在执行的时候,AServlet对象已经存在了。已经被创建出来了。)

    • 用户发送第一次请求的时候,init方法执行之后,Tomcat服务器马上调用AServlet对象的service方法。

  • 用户继续发送第二次请求,控制台输出了以下内容:

AServlet's service method execute!

  • 根据以上输出结果得知,用户在发送第二次,或者第三次,或者第四次请求的时候,Servlet对象并没有新建,还是使用之前创建好的Servlet对象,直接调用该Servlet对象的service方法,这说明:

    • 第一:Servlet对象是单例的(单实例的。但是要注意:Servlet对象是单实例的,但是Servlet类并不符合单例模式。我们称之为假单例。之所以单例是因为Servlet对象的创建我们javaweb程序员管不着,这个对象的创建只能是Tomcat来说了算,Tomcat只创建了一个,所以导致了单例,但是属于假单例。真单例模式,构造方法是私有化的。)

    • 第二:无参数构造方法、init方法只在第一次用户发送请求的时候执行。也就是说无参数构造方法只执行一次。init方法也只被Tomcat服务器调用一次。

    • 第三:只要用户发送一次请求:service方法必然会被Tomcat服务器调用一次。发送100次请求,service方法会被调用100次。

  • 关闭服务器的时候,控制台输出了以下内容:

AServlet's destroy method execute!

  • 通过以上输出内容,可以得出以下结论:

    • Servlet的destroy方法只被Tomcat服务器调用一次。

    • destroy方法是在什么时候被调用的?

      • 在服务器关闭的时候。

      • 因为服务器关闭的时候要销毁AServlet对象的内存。

      • 服务器在销毁AServlet对象内存之前,Tomcat服务器会自动调用AServlet对象的destroy方法。

  • 请问:destroy方法调用的时候,对象销毁了还是没有销毁呢?

    • destroy方法执行的时候AServlet对象还在,没有被销毁。destroy方法执行结束之后,AServlet对象的内存才会被Tomcat释放。

  • Servlet对象更像一个人的一生:

    • Servlet的无参数构造方法执行:标志着你出生了。

    • Servlet对象的init方法的执行:标志着你正在接受教育。

    • Servlet对象的service方法的执行:标志着你已经开始工作了,已经开始为人类提供服务了。

    • Servlet对象的destroy方法的执行:标志着临终。有什么遗言,抓紧的。要不然,来不及了。

  • 关于Servlet类中方法的调用次数?

    • 构造方法只执行一次。

    • init方法只执行一次。

    • service方法:用户发送一次请求则执行一次,发送N次请求则执行N次。

    • destroy方法只执行一次。

  • 当我们Servlet类中编写一个有参数的构造方法,如果没有手动编写无参数构造方法会出现什么问题?

    • 报错了:500错误。

    • 注意:500是一个HTTP协议的错误状态码。

    • 500一般情况下是因为服务器端的Java程序出现了异常。(服务器端的错误都是500错误:服务器内部错误。)

    • 如果没有无参数的构造方法,会导致出现500错误,无法实例化Servlet对象。

    • 所以,一定要注意:在Servlet开发当中,不建议程序员来定义构造方法,因为定义不当,一不小心就会导致无法实例化Servlet对象。

  • 思考:Servlet的无参数构造方法是在对象第一次创建的时候执行,并且只执行一次。init方法也是在对象第一次创建的时候执行,并且只执行一次。那么这个无参数构造方法可以代替掉init方法吗?

    • 不能。

    • Servlet规范中有要求,作为javaweb程序员,编写Servlet类的时候,不建议手动编写构造方法,因为编写构造方法,很容易让无参数构造方法消失,这个操作可能会导致Servlet对象无法实例化。所以init方法是有存在的必要的。

  • init、service、destroy方法中使用最多的是哪个方法?

    • 使用最多就是service方法,service方法是一定要实现的,因为service方法是处理用户请求的核心方法。

    • 什么时候使用init方法呢?

      • init方法很少用。

      • 通常在init方法当中做初始化操作,并且这个初始化操作只需要执行一次。例如:初始化数据库连接池,初始化线程池....

    • 什么时候使用destroy方法呢?

      • destroy方法也很少用。

      • 通常在destroy方法当中,进行资源的关闭。马上对象要被销毁了,还有什么没有关闭的,抓紧时间关闭资源。还有什么资源没保存的,抓紧时间保存一下。

三、GenericServlet

1.我们编写一个Servlet类直接实现Servlet接口有什么缺点?

  • 我们只需要service方法,其他方法大部分情况下是不需要使用的。代码很丑陋。

接口MyInterface

package adapter;public interface MyInterface {void m1();void m2();void m3();void m4();void m5();void m6();void m7();/*** 最常用的是这个方法。*/void core();
}
CustomerService类
package adapter;/*** 对于CustomerService来说,最主要的方法是m2*/
public class CustomerService implements MyInterface{@Overridepublic void m1() {}@Overridepublic void m2() {System.out.println("CustomerService's m2 method execute!");}@Overridepublic void m3() {}@Overridepublic void m4() {}@Overridepublic void m5() {}@Overridepublic void m6() {}@Overridepublic void m7() {}@Overridepublic void core() {}
}
CustomerService2类
package adapter;/*** 对于CustomerService2来说,最主要的方法是m2*/
public class CustomerService2 implements MyInterface{@Overridepublic void m1() {}@Overridepublic void m2() {System.out.println("CustomerService2's m2 method execute!");}@Overridepublic void m3() {}@Overridepublic void m4() {}@Overridepublic void m5() {}@Overridepublic void m6() {}@Overridepublic void m7() {}@Overridepublic void core() {}
}
UserService类
package adapter;/*** 对于UserService来说,core方法是最主要的方法。*/
public class UserService implements MyInterface{@Overridepublic void m1() {}@Overridepublic void m2() {}@Overridepublic void m3() {}@Overridepublic void m4() {}@Overridepublic void m5() {}@Overridepublic void m6() {}@Overridepublic void m7() {}@Overridepublic void core() {System.out.println("UserService's core method execute!");}
}
UserService2类
package adapter;/*** 对于UserService2来说,core方法是最主要的方法。*/
public class UserService2 implements MyInterface{@Overridepublic void m1() {}@Overridepublic void m2() {}@Overridepublic void m3() {}@Overridepublic void m4() {}@Overridepublic void m5() {}@Overridepublic void m6() {}@Overridepublic void m7() {}@Overridepublic void core() {System.out.println("UserService2's core method execute!");}
}

2.适配器设计模式Adapter

  • 手机直接插到220V的电压上,手机直接就报废了。怎么办?可以找一个充电器。这个充电器就是一个适配器。手机连接适配器。适配器连接220V的电压。这样问题就解决了。

接口MyInterface

package adapter2;public interface MyInterface {void m1();void m2();void m3();void m4();void m5();void m6();void m7();void core();
}
CustomerService专用的适配器
package adapter2;/*** CustomerService专用的适配器。*/
public abstract class CustomerAdapter implements MyInterface {@Overridepublic void m1() {}public abstract void m2() ;@Overridepublic void m3() {}@Overridepublic void m4() {}@Overridepublic void m5() {}@Overridepublic void m6() {}@Overridepublic void m7() {}@Overridepublic void core() {}
}

CustomerService类

package adapter2;public class CustomerService extends CustomerAdapter{@Overridepublic void m2() {}
}
UserService类的适配器
package adapter2;// UserService类的适配器。
public abstract class UserAdapter implements MyInterface {@Overridepublic void m1() {}@Overridepublic void m2() {}@Overridepublic void m3() {}@Overridepublic void m4() {}@Overridepublic void m5() {}@Overridepublic void m6() {}@Overridepublic void m7() {}public abstract void core();
}

UserService

package adapter2;public class UserService extends UserAdapter {@Overridepublic void core() {}
}

3.编写一个GenericServlet类,这个类是一个抽象类,其中有一个抽象方法service。

  • GenericServlet实现Servlet接口。

  • GenericServlet是一个适配器。

  • 以后编写的所有Servlet类继承GenericServlet,重写service方法即可。

GenericServlet类
package oop1;import jakarta.servlet.*;import java.io.IOException;/*** 编写一个标准通用的Servlet,起名:GenericServlet* 以后所有的Servlet类都不要直接实现Servlet接口了。* 以后所有的Servlet类都要继承GenericServlet类。* GenericServlet 就是一个适配器。*/
public abstract class GenericServlet implements Servlet {@Override
public void init(ServletConfig servletConfig) throws ServletException{System.out.println("servletConfig对象,小猫咪创建好的:" + servletConfig);
}@Overridepublic ServletConfig getServletConfig() {return null;}/*** 抽象方法,这个方法最常用。所以要求子类必须实现service方法。* @param servletRequest* @param servletResponse* @throws ServletException* @throws IOException*/public abstract void service(ServletRequest servletRequest, ServletResponse servletResponse)throws ServletException, IOException;@Overridepublic String getServletInfo() {return null;}@Overridepublic void destroy() {}
}
LoginServlet类
package oop1;import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;import java.io.IOException;public class LoginServlet extends GenericServlet{@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {System.out.println("正在处理用户登录请求,请稍后。。。。。");}
}
VipServlet 类
package oop1;import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;import java.io.IOException;public class VipServlet extends GenericServlet{@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {System.out.println("Vip可以享受更好的服务。。。。。");}
}

运行结果:

4.思考:GenericServlet类是否需要改造一下?怎么改造?更利于子类程序的编写?

  • 思考第一个问题:我提供了一个GenericServlet之后,init方法还会执行吗?

    • 还会执行。会执行GenericServlet类中的init方法。

  • 思考第二个问题:init方法是谁调用的?

    • Tomcat服务器调用的。

  • 思考第三个问题:init方法中的ServletConfig对象是谁创建的?是谁传过来的?

    • 都是Tomcat干的。

    • Tomcat服务器先创建了ServletConfig对象,然后调用init方法,将ServletConfig对象传给了init方法。

  • 思考一下Tomcat服务器伪代码:

public class Tomcat {public static void main(String[] args){// .....// Tomcat服务器伪代码// 创建LoginServlet对象(通过反射机制,调用无参数构造方法来实例化LoginServlet对象)Class clazz = Class.forName("oop1.LoginServlet");Object obj = clazz.newInstance();// 向下转型Servlet servlet = (Servlet)obj;// 创建ServletConfig对象// Tomcat服务器负责将ServletConfig对象实例化出来。// 多态(Tomcat服务器完全实现了Servlet规范)ServletConfig servletConfig = new org.apache.catalina.core.StandardWrapperFacade();// 调用Servlet的init方法servlet.init(servletConfig);// 调用Servlet的service方法// ....}
}

如何保证servletConfig不仅可以在init方法中用,但是

init方法中的ServletConfig对象是小猫咪创建好的。
* 这个ServletConfig对象目前在init方法的参数上,属于局部变量。
那么ServletConfig对象肯定以后要在service方法中使用,怎么才能保证ServletConfig对象在service方法中能够使用呢?

答:使用成员变量

改造GenericServlet代码:

package oop1;import jakarta.servlet.*;import java.io.IOException;/*** 编写一个标准通用的Servlet,起名:GenericServlet* 以后所有的Servlet类都不要直接实现Servlet接口了。* 以后所有的Servlet类都要继承GenericServlet类。* GenericServlet 就是一个适配器。*/
public abstract class GenericServlet implements Servlet {// 成员变量private ServletConfig config;/*** init方法中的ServletConfig对象是小猫咪创建好的。* 这个ServletConfig对象目前在init方法的参数上,属于局部变量。* 那么ServletConfig对象肯定以后要在service方法中使用,怎么才能保证ServletConfig对象在service方法中能够使用呢?*///加final是为了不让子类重写init@Overridepublic final void init(ServletConfig config) throws ServletException {//System.out.println("servletConfig对象,小猫咪创建好的:" + config);this.config = config;// 调用init()方法this.init();}/*** 这个init方法是供子类重写的。*/public void init(){}@Overridepublic ServletConfig getServletConfig() {return config;}/*** 抽象方法,这个方法最常用。所以要求子类必须实现service方法。* @param servletRequest* @param servletResponse* @throws ServletException* @throws IOException*/public abstract void service(ServletRequest servletRequest, ServletResponse servletResponse)throws ServletException, IOException;@Overridepublic String getServletInfo() {return null;}@Overridepublic void destroy() {}
}

改造的LoginServlet代码

package oop1;import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;import java.io.IOException;public class LoginServlet extends GenericServlet{// 思考一个问题:// 有没有一种可能,需要我在LoginServlet类中重写init方法?// 当然有可能,于是乎就重写了init方法。/*public void init(ServletConfig config) throws ServletException {System.out.println("重写我自己的规则。。。。。");}*/// 父类将原始的init方法final了,我子类没有办法重写这个init方法了。// 如果这个时候我还是希望能够重写init方法,该怎么办呢?@Overridepublic void init(){System.out.println("LoginServlet's init() method execute!");}@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {System.out.println("正在处理用户登录请求,请稍后。。。。。");// 想在LoginServlet子类中使用ServletConfig对象怎么办?ServletConfig config = this.getServletConfig();System.out.println("service方法中是否可以获取到ServletConfig对象?" + config);}
}

运行结果:

四、ServletConfig接口详解

1.

ServletConfig
*   1. ServletConfig是什么?
*      jakarta.servlet.ServletConfig
*      显然ServletConfig是Servlet规范中的一员。
*      ServletConfig是一个接口。(jakarta.servlet.Servlet是一个接口。)
*   2. 谁去实现了这个接口呢? WEB服务器实现了
*      public class org.apache.catalina.core.StandardWrapperFacade implements ServletConfig {}
*      结论:Tomcat服务器实现了ServletConfig接口。
*      思考:如果把Tomcat服务器换成jetty服务器,输出ServletConfig对象的时候,还是这个结果吗?
*          不一定一样,包名类名可能和Tomcat不一样。但是他们都实现了ServletConfig这个规范。
ConfigTestServlet 类
package oop1;import jakarta.servlet.*;import java.io.IOException;
import java.io.PrintWriter;/*
* ServletConfig*   1. ServletConfig是什么?*      jakarta.servlet.ServletConfig*      显然ServletConfig是Servlet规范中的一员。*      ServletConfig是一个接口。(jakarta.servlet.Servlet是一个接口。)*   2. 谁去实现了这个接口呢? WEB服务器实现了*      public class org.apache.catalina.core.StandardWrapperFacade implements ServletConfig {}*      结论:Tomcat服务器实现了ServletConfig接口。*      思考:如果把Tomcat服务器换成jetty服务器,输出ServletConfig对象的时候,还是这个结果吗?*          不一定一样,包名类名可能和Tomcat不一样。但是他们都实现了ServletConfig这个规范。
* */
public class ConfigTestServlet extends GenericServlet {@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {servletResponse.setContentType("text/html");PrintWriter out=servletResponse.getWriter();//获取ServletConfig对象ServletConfig config=this.getServletConfig();//输出该对象out.print("Servlet对象是"+config);}
}

运行结果:

2.

*   3. 一个Servlet对象中有一个ServletConfig对象。(Servlet和ServletConfig对象是一对一。)
*      100个Servlet,就应该有100个ServletConfig对象。
*   4. ServletConfig对象是谁创建的?在什么时候创建的?
*      Tomcat服务器(WEB服务器)创建了ServletConfig对象。
*      在创建Servlet对象的时候,同时创建ServletConfig对象。
*   5. ServletConfig接口到底是干啥的?有什么用呢?
*      Config是哪个单词的缩写?
*          Configuration
*      ServletConfig对象被翻译为:Servlet对象的配置信息对象。
*      一个Servlet对象就有一个配置信息对象。
*      两个Servlet对象就有两个配置信息对象。

验证:

ConfigTestServlet2类

package oop1;import jakarta.servlet.*;import java.io.IOException;
import java.io.PrintWriter;public class ConfigTestServlet2 extends GenericServlet {@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {servletResponse.setContentType("text/html");PrintWriter out=servletResponse.getWriter();//获取ServletConfig对象ServletConfig config=this.getServletConfig();//输出该对象out.print("Servlet对象是"+config);}
}

运行结果:

可以看到重启服务器后,2个ServletConfig对象的地址不一致

3.

6. ServletConfig对象中到底包装了什么信息呢?

package oop1;import jakarta.servlet.*;import java.io.IOException;
import java.io.PrintWriter;/*
* ServletConfig*   1. ServletConfig是什么?*      jakarta.servlet.ServletConfig*      显然ServletConfig是Servlet规范中的一员。*      ServletConfig是一个接口。(jakarta.servlet.Servlet是一个接口。)*   2. 谁去实现了这个接口呢? WEB服务器实现了*      public class org.apache.catalina.core.StandardWrapperFacade implements ServletConfig {}*      结论:Tomcat服务器实现了ServletConfig接口。*      思考:如果把Tomcat服务器换成jetty服务器,输出ServletConfig对象的时候,还是这个结果吗?*          不一定一样,包名类名可能和Tomcat不一样。但是他们都实现了ServletConfig这个规范。**  *   3. 一个Servlet对象中有一个ServletConfig对象。(Servlet和ServletConfig对象是一对一。)*      100个Servlet,就应该有100个ServletConfig对象。*   4. ServletConfig对象是谁创建的?在什么时候创建的?*      Tomcat服务器(WEB服务器)创建了ServletConfig对象。*      在创建Servlet对象的时候,同时创建ServletConfig对象。*   5. ServletConfig接口到底是干啥的?有什么用呢?*      Config是哪个单词的缩写?*          Configuration*      ServletConfig对象被翻译为:Servlet对象的配置信息对象。*      一个Servlet对象就有一个配置信息对象。*      两个Servlet对象就有两个配置信息对象。
* */
public class ConfigTestServlet extends GenericServlet {@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {servletResponse.setContentType("text/html");PrintWriter out=servletResponse.getWriter();//获取ServletConfig对象ServletConfig config=this.getServletConfig();//输出该对象out.print("Servlet对象是"+config);out.print("<br>");// 获取<servlet-name></servlet-name>String servletName = config.getServletName();out.print("<servlet-name>"+servletName+"</servlet-name>");out.print("<br>");}
}

sevlet初始化参数信息

<?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_4_0.xsd"version="4.0"><servlet><servlet-name>config2</servlet-name><servlet-class>oop1.ConfigTestServlet</servlet-class><!--<load-on-startup>0</load-on-startup>--></servlet><servlet-mapping><servlet-name>config2</servlet-name><url-pattern>/con2</url-pattern></servlet-mapping><servlet><servlet-name>config</servlet-name><servlet-class>oop1.ConfigTestServlet</servlet-class><!--<load-on-startup>0</load-on-startup>--><!--这里是可以配置一个Servlet对象的初始化信息的。--><init-param><param-name>driver</param-name><param-value>com.mysql.cj.jdbc.Driver</param-value></init-param><init-param><param-name>url</param-name><param-value>jdbc:mysql://localhost:3306/bjpowernode</param-value></init-param><init-param><param-name>user</param-name><param-value>root</param-value></init-param><init-param><param-name>password</param-name><param-value>abc123</param-value></init-param></servlet><servlet-mapping><servlet-name>config</servlet-name><url-pattern>/con</url-pattern></servlet-mapping>
</web-app>

4.

*   6. ServletConfig对象中到底包装了什么信息呢?
*      <servlet>
*         <servlet-name>configTest</servlet-name>
*         <servlet-class>com.bjpowernode.javaweb.servlet.ConfigTestServlet</servlet-class>
*     </servlet>
*     ServletConfig对象中包装的信息是:
*          web.xml文件中<servlet></servlet>标签的配置信息。
*
*     Tomcat小猫咪解析web.xml文件,将web.xml文件中<servlet></servlet>标签中的配置信息自动包装到ServletConfig对象中。
*
*   7. ServletConfig接口中有哪些方法?
*      <servlet>
*         <servlet-name>configTest</servlet-name>
*         <servlet-class>com.bjpowernode.javaweb.servlet.ConfigTestServlet</servlet-class>
*         <!--这里是可以配置一个Servlet对象的初始化信息的。-->
*         <init-param>
*             <param-name>driver</param-name>
*             <param-value>com.mysql.cj.jdbc.Driver</param-value>
*         </init-param>
*         <init-param>
*             <param-name>url</param-name>
*             <param-value>jdbc:mysql://localhost:3306/bjpowernode</param-value>
*         </init-param>
*         <init-param>
*             <param-name>user</param-name>
*             <param-value>root</param-value>
*         </init-param>
*         <init-param>
*             <param-name>password</param-name>
*             <param-value>root1234</param-value>
*         </init-param>
*     </servlet>
*     以上<servlet></servlet>标签中的<init-param></init-param>是初始化参数。这个初始化参数信息会自动被小猫咪封装到ServletConfig对象当中

ConfigTestServlet类:

package oop1;import jakarta.servlet.*;import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;/*
* ServletConfig*   1. ServletConfig是什么?*      jakarta.servlet.ServletConfig*      显然ServletConfig是Servlet规范中的一员。*      ServletConfig是一个接口。(jakarta.servlet.Servlet是一个接口。)*   2. 谁去实现了这个接口呢? WEB服务器实现了*      public class org.apache.catalina.core.StandardWrapperFacade implements ServletConfig {}*      结论:Tomcat服务器实现了ServletConfig接口。*      思考:如果把Tomcat服务器换成jetty服务器,输出ServletConfig对象的时候,还是这个结果吗?*          不一定一样,包名类名可能和Tomcat不一样。但是他们都实现了ServletConfig这个规范。**  *   3. 一个Servlet对象中有一个ServletConfig对象。(Servlet和ServletConfig对象是一对一。)*      100个Servlet,就应该有100个ServletConfig对象。*   4. ServletConfig对象是谁创建的?在什么时候创建的?*      Tomcat服务器(WEB服务器)创建了ServletConfig对象。*      在创建Servlet对象的时候,同时创建ServletConfig对象。*   5. ServletConfig接口到底是干啥的?有什么用呢?*      Config是哪个单词的缩写?*          Configuration*      ServletConfig对象被翻译为:Servlet对象的配置信息对象。*      一个Servlet对象就有一个配置信息对象。*      两个Servlet对象就有两个配置信息对象。* *   6. ServletConfig对象中到底包装了什么信息呢?*      <servlet>*         <servlet-name>configTest</servlet-name>*         <servlet-class>com.bjpowernode.javaweb.servlet.ConfigTestServlet</servlet-class>*     </servlet>*     ServletConfig对象中包装的信息是:*          web.xml文件中<servlet></servlet>标签的配置信息。**     Tomcat小猫咪解析web.xml文件,将web.xml文件中<servlet></servlet>标签中的配置信息自动包装到ServletConfig对象中。**   7. ServletConfig接口中有哪些方法?*      <servlet>*         <servlet-name>configTest</servlet-name>*         <servlet-class>com.bjpowernode.javaweb.servlet.ConfigTestServlet</servlet-class>*         <!--这里是可以配置一个Servlet对象的初始化信息的。-->*         <init-param>*             <param-name>driver</param-name>*             <param-value>com.mysql.cj.jdbc.Driver</param-value>*         </init-param>*         <init-param>*             <param-name>url</param-name>*             <param-value>jdbc:mysql://localhost:3306/bjpowernode</param-value>*         </init-param>*         <init-param>*             <param-name>user</param-name>*             <param-value>root</param-value>*         </init-param>*         <init-param>*             <param-name>password</param-name>*             <param-value>root1234</param-value>*         </init-param>*     </servlet>*     以上<servlet></servlet>标签中的<init-param></init-param>是初始化参数。这个初始化参数信息会自动被小猫咪封装到ServletConfig对象当中
* */
public class ConfigTestServlet extends GenericServlet {@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {servletResponse.setContentType("text/html");PrintWriter out=servletResponse.getWriter();//获取ServletConfig对象ServletConfig config=this.getServletConfig();//输出该对象out.print("Servlet对象是"+config);out.print("<br>");// 获取<servlet-name></servlet-name>String servletName = config.getServletName();out.print("<servlet-name>"+servletName+"</servlet-name>");out.print("<br>");// 通过ServletConfig对象的两个方法,可以获取到web.xml文件中的初始化参数配置信息。// java.util.Enumeration<java.lang.String>	getInitParameterNames() 获取所有的初始化参数的nameEnumeration<String> initParameterNames = config.getInitParameterNames();// 遍历集合while(initParameterNames.hasMoreElements()) { // 是否有更多元素String parameterName = initParameterNames.nextElement(); // 取元素String parameterVal = config.getInitParameter(parameterName); // 通过name获取valueout.print(parameterName + "=" + parameterVal);out.print("<br>");}// java.lang.String	getInitParameter(java.lang.String name) 通过初始化参数的name获取value/*String driver = config.getInitParameter("driver");out.print(driver);*/}
}

ConfigTestServlet2类:

package oop1;import jakarta.servlet.*;import java.io.IOException;
import java.io.PrintWriter;public class ConfigTestServlet2 extends GenericServlet {@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {servletResponse.setContentType("text/html");PrintWriter out=servletResponse.getWriter();//获取ServletConfig对象ServletConfig config=this.getServletConfig();//输出该对象out.print("Servlet对象是"+config);String value = config.getInitParameter("key");out.print("<br>" + value);}
}

web.xml

<?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_4_0.xsd"version="4.0"><servlet><servlet-name>config2</servlet-name><servlet-class>oop1.ConfigTestServlet</servlet-class><!--<load-on-startup>0</load-on-startup>--><init-param><param-name>driver2</param-name><param-value>com.mysql.cj.jdbc.Driver2</param-value></init-param><init-param><param-name>url</param-name><param-value>jdbc:mysql://localhost:3306/bjpowernode2</param-value></init-param><init-param><param-name>user2</param-name><param-value>root2</param-value></init-param><init-param><param-name>password2</param-name><param-value>abc123</param-value></init-param></servlet><servlet-mapping><servlet-name>config2</servlet-name><url-pattern>/con2</url-pattern></servlet-mapping><servlet><servlet-name>config</servlet-name><servlet-class>oop1.ConfigTestServlet</servlet-class><!--<load-on-startup>0</load-on-startup>--><!--这里是可以配置一个Servlet对象的初始化信息的。--><init-param><param-name>driver</param-name><param-value>com.mysql.cj.jdbc.Driver</param-value></init-param><init-param><param-name>url</param-name><param-value>jdbc:mysql://localhost:3306/bjpowernode</param-value></init-param><init-param><param-name>user</param-name><param-value>root</param-value></init-param><init-param><param-name>password</param-name><param-value>abc123</param-value></init-param></servlet><servlet-mapping><servlet-name>config</servlet-name><url-pattern>/con</url-pattern></servlet-mapping>
</web-app>

上面代码照旧,ConfigTestServlet代码添加如下

package oop1;import jakarta.servlet.*;import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;/*
* ServletConfig*   1. ServletConfig是什么?*      jakarta.servlet.ServletConfig*      显然ServletConfig是Servlet规范中的一员。*      ServletConfig是一个接口。(jakarta.servlet.Servlet是一个接口。)*   2. 谁去实现了这个接口呢? WEB服务器实现了*      public class org.apache.catalina.core.StandardWrapperFacade implements ServletConfig {}*      结论:Tomcat服务器实现了ServletConfig接口。*      思考:如果把Tomcat服务器换成jetty服务器,输出ServletConfig对象的时候,还是这个结果吗?*          不一定一样,包名类名可能和Tomcat不一样。但是他们都实现了ServletConfig这个规范。**  *   3. 一个Servlet对象中有一个ServletConfig对象。(Servlet和ServletConfig对象是一对一。)*      100个Servlet,就应该有100个ServletConfig对象。*   4. ServletConfig对象是谁创建的?在什么时候创建的?*      Tomcat服务器(WEB服务器)创建了ServletConfig对象。*      在创建Servlet对象的时候,同时创建ServletConfig对象。*   5. ServletConfig接口到底是干啥的?有什么用呢?*      Config是哪个单词的缩写?*          Configuration*      ServletConfig对象被翻译为:Servlet对象的配置信息对象。*      一个Servlet对象就有一个配置信息对象。*      两个Servlet对象就有两个配置信息对象。* *   6. ServletConfig对象中到底包装了什么信息呢?*      <servlet>*         <servlet-name>configTest</servlet-name>*         <servlet-class>com.bjpowernode.javaweb.servlet.ConfigTestServlet</servlet-class>*     </servlet>*     ServletConfig对象中包装的信息是:*          web.xml文件中<servlet></servlet>标签的配置信息。**     Tomcat小猫咪解析web.xml文件,将web.xml文件中<servlet></servlet>标签中的配置信息自动包装到ServletConfig对象中。**   7. ServletConfig接口中有哪些方法?*      <servlet>*         <servlet-name>configTest</servlet-name>*         <servlet-class>com.bjpowernode.javaweb.servlet.ConfigTestServlet</servlet-class>*         <!--这里是可以配置一个Servlet对象的初始化信息的。-->*         <init-param>*             <param-name>driver</param-name>*             <param-value>com.mysql.cj.jdbc.Driver</param-value>*         </init-param>*         <init-param>*             <param-name>url</param-name>*             <param-value>jdbc:mysql://localhost:3306/bjpowernode</param-value>*         </init-param>*         <init-param>*             <param-name>user</param-name>*             <param-value>root</param-value>*         </init-param>*         <init-param>*             <param-name>password</param-name>*             <param-value>root1234</param-value>*         </init-param>*     </servlet>*     以上<servlet></servlet>标签中的<init-param></init-param>是初始化参数。这个初始化参数信息会自动被小猫咪封装到ServletConfig对象当中
* */
public class ConfigTestServlet extends GenericServlet {@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {servletResponse.setContentType("text/html");PrintWriter out=servletResponse.getWriter();//获取ServletConfig对象ServletConfig config=this.getServletConfig();//输出该对象out.print("Servlet对象是"+config);out.print("<br>");// 获取<servlet-name></servlet-name>String servletName = config.getServletName();out.print("<servlet-name>"+servletName+"</servlet-name>");out.print("<br>");// 通过ServletConfig对象的两个方法,可以获取到web.xml文件中的初始化参数配置信息。// java.util.Enumeration<java.lang.String>	getInitParameterNames() 获取所有的初始化参数的nameEnumeration<String> initParameterNames = config.getInitParameterNames();// 遍历集合while(initParameterNames.hasMoreElements()) { // 是否有更多元素String parameterName = initParameterNames.nextElement(); // 取元素String parameterVal = config.getInitParameter(parameterName); // 通过name获取valueout.print(parameterName + "=" + parameterVal);out.print("<br>");}// java.lang.String	getInitParameter(java.lang.String name) 通过初始化参数的name获取value/*String driver = config.getInitParameter("driver");out.print(driver);*/// 实际上获取一个Servlet对象的初始化参数,可以不用获取ServletConfig对象。直接通过this也可以。Enumeration<String> names = this.getInitParameterNames();while(names.hasMoreElements()){String name = names.nextElement();String value = this.getInitParameter(name);// 打印到后台System.out.println(name + "=" + value);}}
}

5.

  8. ServletConfig接口中有4个方法:
*      第1个方法:
*          public String getInitParameter(String name);
*      第2个方法:
*          public Enumeration<String> getInitParameterNames();
*      第3个方法:
*          public ServletContext getServletContext();
*      第4个方法:
*          public String getServletName();
*
*      以上的4个方法,在自己编写的Servlet类当中也可以使用this去调用。(这个Servlet继承了GenericServlet)

上面代码照旧,ConfigTestServlet代码添加如下

package oop1;import jakarta.servlet.*;import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;/*
* ServletConfig*   1. ServletConfig是什么?*      jakarta.servlet.ServletConfig*      显然ServletConfig是Servlet规范中的一员。*      ServletConfig是一个接口。(jakarta.servlet.Servlet是一个接口。)*   2. 谁去实现了这个接口呢? WEB服务器实现了*      public class org.apache.catalina.core.StandardWrapperFacade implements ServletConfig {}*      结论:Tomcat服务器实现了ServletConfig接口。*      思考:如果把Tomcat服务器换成jetty服务器,输出ServletConfig对象的时候,还是这个结果吗?*          不一定一样,包名类名可能和Tomcat不一样。但是他们都实现了ServletConfig这个规范。**  *   3. 一个Servlet对象中有一个ServletConfig对象。(Servlet和ServletConfig对象是一对一。)*      100个Servlet,就应该有100个ServletConfig对象。*   4. ServletConfig对象是谁创建的?在什么时候创建的?*      Tomcat服务器(WEB服务器)创建了ServletConfig对象。*      在创建Servlet对象的时候,同时创建ServletConfig对象。*   5. ServletConfig接口到底是干啥的?有什么用呢?*      Config是哪个单词的缩写?*          Configuration*      ServletConfig对象被翻译为:Servlet对象的配置信息对象。*      一个Servlet对象就有一个配置信息对象。*      两个Servlet对象就有两个配置信息对象。* *   6. ServletConfig对象中到底包装了什么信息呢?*      <servlet>*         <servlet-name>configTest</servlet-name>*         <servlet-class>com.bjpowernode.javaweb.servlet.ConfigTestServlet</servlet-class>*     </servlet>*     ServletConfig对象中包装的信息是:*          web.xml文件中<servlet></servlet>标签的配置信息。**     Tomcat小猫咪解析web.xml文件,将web.xml文件中<servlet></servlet>标签中的配置信息自动包装到ServletConfig对象中。**   7. ServletConfig接口中有哪些方法?*      <servlet>*         <servlet-name>configTest</servlet-name>*         <servlet-class>com.bjpowernode.javaweb.servlet.ConfigTestServlet</servlet-class>*         <!--这里是可以配置一个Servlet对象的初始化信息的。-->*         <init-param>*             <param-name>driver</param-name>*             <param-value>com.mysql.cj.jdbc.Driver</param-value>*         </init-param>*         <init-param>*             <param-name>url</param-name>*             <param-value>jdbc:mysql://localhost:3306/bjpowernode</param-value>*         </init-param>*         <init-param>*             <param-name>user</param-name>*             <param-value>root</param-value>*         </init-param>*         <init-param>*             <param-name>password</param-name>*             <param-value>root1234</param-value>*         </init-param>*     </servlet>*     以上<servlet></servlet>标签中的<init-param></init-param>是初始化参数。这个初始化参数信息会自动被小猫咪封装到ServletConfig对象当中
* */
public class ConfigTestServlet extends GenericServlet {@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {servletResponse.setContentType("text/html");PrintWriter out=servletResponse.getWriter();//获取ServletConfig对象ServletConfig config=this.getServletConfig();//输出该对象out.print("Servlet对象是"+config);out.print("<br>");// 获取<servlet-name></servlet-name>String servletName = config.getServletName();out.print("<servlet-name>"+servletName+"</servlet-name>");out.print("<br>");// 通过ServletConfig对象的两个方法,可以获取到web.xml文件中的初始化参数配置信息。// java.util.Enumeration<java.lang.String>	getInitParameterNames() 获取所有的初始化参数的nameEnumeration<String> initParameterNames = config.getInitParameterNames();// 遍历集合while(initParameterNames.hasMoreElements()) { // 是否有更多元素String parameterName = initParameterNames.nextElement(); // 取元素String parameterVal = config.getInitParameter(parameterName); // 通过name获取valueout.print(parameterName + "=" + parameterVal);out.print("<br>");}// java.lang.String	getInitParameter(java.lang.String name) 通过初始化参数的name获取value/*String driver = config.getInitParameter("driver");out.print(driver);*/// 实际上获取一个Servlet对象的初始化参数,可以不用获取ServletConfig对象。直接通过this也可以。Enumeration<String> names = this.getInitParameterNames();while(names.hasMoreElements()){String name = names.nextElement();String value = this.getInitParameter(name);// 打印到后台System.out.println(name + "=" + value);}// 怎么获取ServletContext对象呢?// 第一种方式:通过ServletConfig对象获取ServletContext对象。ServletContext application = config.getServletContext();// 输出out.print("<br>" + application); //org.apache.catalina.core.ApplicationContextFacade@19187bbb// 第二种方式:通过this也可以获取ServletContext对象。ServletContext application2 = this.getServletContext();out.print("<br>" + application2); //org.apache.catalina.core.ApplicationContextFacade@19187bbb}
}

  • 什么是ServletConfig?

    • Servlet对象的配置信息对象。

    • ServletConfig对象中封装了<servlet></servlet>标签中的配置信息。(web.xml文件中servlet的配置信息)

  • 一个Servlet对应一个ServletConfig对象。

  • Servlet对象是Tomcat服务器创建,并且ServletConfig对象也是Tomcat服务器创建。并且默认情况下,他们都是在用户发送第一次请求的时候创建。

  • Tomcat服务器调用Servlet对象的init方法的时候需要传一个ServletConfig对象的参数给init方法。

  • ServletConfig接口的实现类是Tomcat服务器给实现的。(Tomcat服务器说的就是WEB服务器。)

  • ServletConfig接口有哪些常用的方法?

public String getInitParameter(String name); // 通过初始化参数的name获取value
public Enumeration<String> getInitParameterNames(); // 获取所有的初始化参数的name
public ServletContext getServletContext(); // 获取ServletContext对象
public String getServletName(); // 获取Servlet的name
  • 以上方法在Servlet类当中,都可以使用this去调用。因为GenericServlet实现了ServletConfig接口。

五、ServletContext接口详解

1.

* ServletContext
* 1. ServletContext是什么?
*  ServletContext是接口,是Servlet规范中的一员。
* 2. ServletContext是谁实现的?
*  Tomcat服务器(WEB服务器)实现了ServletContext接口。
*  public class org.apache.catalina.core.ApplicationContextFacade implements ServletContext {}
* 3. ServletContext对象是谁创建的?在什么时候创建的?
*  ServletContext对象在WEB服务器启动的时候创建。
*  ServletContext对象是WEB服务器创建的。
*  对于一个webapp来说,ServletContext对象只有一个。
*  ServletContext对象在服务器关闭的时候销毁。
* 4. ServletContext怎么理解?
*  context是什么意思?
*      Servlet对象的环境对象。(Servlet对象的上下文对象。)
*  ServletContext对象其实对应的就是整个web.xml文件。
*  50个学生,每个学生都是一个Servlet,这50个学生都在同一个教室当中。那么这个教室就相当于ServletContext对象。
*  放在ServletContext对象当中的数据,所有Servlet一定是共享的。
*  比如:一个教室中的空调是所有学生共享的,一个教室中的语文老师是所有学生共享的。
*  Tomcat是一个容器,一个容器当中可以放多个webapp,一个webapp对应一个ServletContext对象。

AServlet 类

package oop1;import jakarta.servlet.*;import javax.swing.text.GapContent;
import java.io.IOException;
import java.io.PrintWriter;/*** ServletContext* 1. ServletContext是什么?*  ServletContext是接口,是Servlet规范中的一员。* 2. ServletContext是谁实现的?*  Tomcat服务器(WEB服务器)实现了ServletContext接口。*  public class org.apache.catalina.core.ApplicationContextFacade implements ServletContext {}* 3. ServletContext对象是谁创建的?在什么时候创建的?*  ServletContext对象在WEB服务器启动的时候创建。*  ServletContext对象是WEB服务器创建的。*  对于一个webapp来说,ServletContext对象只有一个。*  ServletContext对象在服务器关闭的时候销毁。* 4. ServletContext怎么理解?*  context是什么意思?*      Servlet对象的环境对象。(Servlet对象的上下文对象。)*  ServletContext对象其实对应的就是整个web.xml文件。*  50个学生,每个学生都是一个Servlet,这50个学生都在同一个教室当中。那么这个教室就相当于ServletContext对象。*  放在ServletContext对象当中的数据,所有Servlet一定是共享的。*  比如:一个教室中的空调是所有学生共享的,一个教室中的语文老师是所有学生共享的。*  Tomcat是一个容器,一个容器当中可以放多个webapp,一个webapp对应一个ServletContext对象。*/
public class AServlet extends GenericServlet {@Overridepublic void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {response.setContentType("text/html");PrintWriter out = response.getWriter();// 获取ServletContext对象ServletContext application = this.getServletContext();out.print("ServletContext对象是:" + application + "<br>");}
}

BServlet类

package oop1;import jakarta.servlet.*;import java.io.IOException;
import java.io.PrintWriter;public class BServlet extends GenericServlet {@Overridepublic void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {response.setContentType("text/html");PrintWriter out = response.getWriter();// 获取ServletContext对象ServletContext application = this.getServletContext();out.print("ServletContext对象是:" + application + "<br>");}
}

⑴. ServletContext 是什么?

  • ServletContext 是“Web应用的全局管家”
    每个Web应用启动时,容器(如Tomcat)会创建一个ServletContext对象,它代表整个Web应用,所有Servlet共享同一个ServletContext

  • 作用
    用于存储全局配置(如web.xml中的参数)、共享数据(所有用户和Servlet都能访问)等。


⑵. 为什么两个Servlet输出的ServletContext对象相同?

  • 同一个Web应用,同一个ServletContext
    只要AServletBServlet部署在同一个Web应用中,它们获取的ServletContext一定是同一个对象。

pom.xml是maven构建的相当于这里的lib

  • 一个Servlet对象对应一个ServletConfig。100个Servlet对象则对应100个ServletConfig对象。

  • 只要在同一个webapp当中,只要在同一个应用当中,所有的Servlet对象都是共享同一个ServletContext对象的。

  • ServletContext对象在服务器启动阶段创建,在服务器关闭的时候销毁。这就是ServletContext对象的生命周期。ServletContext对象是应用级对象。

  • Tomcat服务器中有一个webapps,这个webapps下可以存放webapp,可以存放多个webapp,假设有100个webapp,那么就有100个ServletContext对象。但是,总之,一个应用,一个webapp肯定是只有一个ServletContext对象。

  • ServletContext被称为Servlet上下文对象。(Servlet对象的四周环境对象。)

  • 一个ServletContext对象通常对应的是一个web.xml文件。

  • ServletContext对应显示生活中的什么例子呢?

    • 一个教室里有多个学生,那么每一个学生就是一个Servlet,这些学生都在同一个教室当中,那么我们可以把这个教室叫做ServletContext对象。那么也就是说放在这个ServletContext对象(环境)当中的数据,在同一个教室当中,物品都是共享的。比如:教室中有一个空调,所有的学生都可以操作。可见,空调是共享的。因为空调放在教室当中。教室就是ServletContext对象。

  • ServletContext是一个接口,Tomcat服务器对ServletContext接口进行了实现。

    • ServletContext对象的创建也是Tomcat服务器来完成的。启动webapp的时候创建的。

  • ServletContext接口中有哪些常用的方法?

public String getInitParameter(String name); // 通过初始化参数的name获取value
public Enumeration<String> getInitParameterNames(); // 获取所有的初始化参数的name

写在web-app中

<!--以上两个方法是ServletContext对象的方法,这个方法获取的是什么信息?是以下的配置信息-->
<context-param><param-name>pageSize</param-name><param-value>10</param-value>
</context-param>
<context-param><param-name>startIndex</param-name><param-value>0</param-value>
</context-param>
<!--注意:以上的配置信息属于应用级的配置信息,一般一个项目中共享的配置信息会放到以上的标签当中。-->
<!--如果你的配置信息只是想给某一个servlet作为参考,那么你配置到servlet标签当中即可,使用ServletConfig对象来获取。-->

AServlet类

package oop1;import jakarta.servlet.*;import javax.swing.text.GapContent;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;/*** ServletContext* 1. ServletContext是什么?*  ServletContext是接口,是Servlet规范中的一员。* 2. ServletContext是谁实现的?*  Tomcat服务器(WEB服务器)实现了ServletContext接口。*  public class org.apache.catalina.core.ApplicationContextFacade implements ServletContext {}* 3. ServletContext对象是谁创建的?在什么时候创建的?*  ServletContext对象在WEB服务器启动的时候创建。*  ServletContext对象是WEB服务器创建的。*  对于一个webapp来说,ServletContext对象只有一个。*  ServletContext对象在服务器关闭的时候销毁。* 4. ServletContext怎么理解?*  context是什么意思?*      Servlet对象的环境对象。(Servlet对象的上下文对象。)*  ServletContext对象其实对应的就是整个web.xml文件。*  50个学生,每个学生都是一个Servlet,这50个学生都在同一个教室当中。那么这个教室就相当于ServletContext对象。*  放在ServletContext对象当中的数据,所有Servlet一定是共享的。*  比如:一个教室中的空调是所有学生共享的,一个教室中的语文老师是所有学生共享的。*  Tomcat是一个容器,一个容器当中可以放多个webapp,一个webapp对应一个ServletContext对象。*/
public class AServlet extends GenericServlet {@Overridepublic void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {response.setContentType("text/html");PrintWriter out = response.getWriter();// 获取ServletContext对象ServletContext application = this.getServletContext();out.print("ServletContext对象是:" + application + "<br>");// 获取上下文的初始化参数Enumeration<String> initParameterNames = application.getInitParameterNames();while(initParameterNames.hasMoreElements()){String name = initParameterNames.nextElement();String value = application.getInitParameter(name);out.print(name + "=" + value + "<br>");}}
}

web.xml

<?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_4_0.xsd"version="4.0"><!--上下文的初始化参数,以下的这些配置信息,可以通过ServletContext对象来获取--><context-param><param-name>pageSize</param-name><param-value>10</param-value></context-param><context-param><param-name>startIndex</param-name><param-value>0</param-value></context-param><servlet><servlet-name>aservlet</servlet-name><servlet-class>oop1.AServlet</servlet-class><!--<load-on-startup>1</load-on-startup>--></servlet><servlet-mapping><servlet-name>aservlet</servlet-name><url-pattern>/a</url-pattern></servlet-mapping><servlet><servlet-name>bservlet</servlet-name><servlet-class>oop1.BServlet</servlet-class><!--<load-on-startup>0</load-on-startup>--></servlet><servlet-mapping><servlet-name>bservlet</servlet-name><url-pattern>/b</url-pattern></servlet-mapping></web-app>

运行结果:

2.获取context path (获取应用上下文的根)(动态的获取)

// 获取应用的根路径(非常重要),因为在java源代码当中有一些地方可能会需要应用的根路径,这个方法可以动态获取应用的根路径
// 在java源码当中,不要将应用的根路径写死,因为你永远都不知道这个应用在最终部署的时候,起一个什么名字。

// 获取应用的根路径(非常重要),因为在java源代码当中有一些地方可能会需要应用的根路径,这个方法可以动态获取应用的根路径
// 在java源码当中,不要将应用的根路径写死,因为你永远都不知道这个应用在最终部署的时候,起一个什么名字。
public String getContextPath();
//String contextPath = application.getContextPath();

AServlet类添加代码如下,其他保持不变

package oop1;import jakarta.servlet.*;import javax.swing.text.GapContent;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;/*** ServletContext* 1. ServletContext是什么?*  ServletContext是接口,是Servlet规范中的一员。* 2. ServletContext是谁实现的?*  Tomcat服务器(WEB服务器)实现了ServletContext接口。*  public class org.apache.catalina.core.ApplicationContextFacade implements ServletContext {}* 3. ServletContext对象是谁创建的?在什么时候创建的?*  ServletContext对象在WEB服务器启动的时候创建。*  ServletContext对象是WEB服务器创建的。*  对于一个webapp来说,ServletContext对象只有一个。*  ServletContext对象在服务器关闭的时候销毁。* 4. ServletContext怎么理解?*  context是什么意思?*      Servlet对象的环境对象。(Servlet对象的上下文对象。)*  ServletContext对象其实对应的就是整个web.xml文件。*  50个学生,每个学生都是一个Servlet,这50个学生都在同一个教室当中。那么这个教室就相当于ServletContext对象。*  放在ServletContext对象当中的数据,所有Servlet一定是共享的。*  比如:一个教室中的空调是所有学生共享的,一个教室中的语文老师是所有学生共享的。*  Tomcat是一个容器,一个容器当中可以放多个webapp,一个webapp对应一个ServletContext对象。*/
public class AServlet extends GenericServlet {@Overridepublic void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {response.setContentType("text/html");PrintWriter out = response.getWriter();// 获取ServletContext对象ServletContext application = this.getServletContext();out.print("ServletContext对象是:" + application + "<br>");// 获取上下文的初始化参数Enumeration<String> initParameterNames = application.getInitParameterNames();while(initParameterNames.hasMoreElements()){String name = initParameterNames.nextElement();String value = application.getInitParameter(name);out.print(name + "=" + value + "<br>");}// 获取context path (获取应用上下文的根)String contextPath = application.getContextPath();out.print(contextPath + "<br>");}
}

3.获取文件的绝对路径(真实路径)

// 获取文件的绝对路径(真实路径)
public String getRealPath(String path);

 AServlet类:

package oop1;import jakarta.servlet.*;import javax.swing.text.GapContent;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;/*** ServletContext* 1. ServletContext是什么?*  ServletContext是接口,是Servlet规范中的一员。* 2. ServletContext是谁实现的?*  Tomcat服务器(WEB服务器)实现了ServletContext接口。*  public class org.apache.catalina.core.ApplicationContextFacade implements ServletContext {}* 3. ServletContext对象是谁创建的?在什么时候创建的?*  ServletContext对象在WEB服务器启动的时候创建。*  ServletContext对象是WEB服务器创建的。*  对于一个webapp来说,ServletContext对象只有一个。*  ServletContext对象在服务器关闭的时候销毁。* 4. ServletContext怎么理解?*  context是什么意思?*      Servlet对象的环境对象。(Servlet对象的上下文对象。)*  ServletContext对象其实对应的就是整个web.xml文件。*  50个学生,每个学生都是一个Servlet,这50个学生都在同一个教室当中。那么这个教室就相当于ServletContext对象。*  放在ServletContext对象当中的数据,所有Servlet一定是共享的。*  比如:一个教室中的空调是所有学生共享的,一个教室中的语文老师是所有学生共享的。*  Tomcat是一个容器,一个容器当中可以放多个webapp,一个webapp对应一个ServletContext对象。*/
public class AServlet extends GenericServlet {@Overridepublic void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {response.setContentType("text/html");PrintWriter out = response.getWriter();// 获取ServletContext对象ServletContext application = this.getServletContext();out.print("ServletContext对象是:" + application + "<br>");// 获取上下文的初始化参数Enumeration<String> initParameterNames = application.getInitParameterNames();while(initParameterNames.hasMoreElements()){String name = initParameterNames.nextElement();String value = application.getInitParameter(name);out.print(name + "=" + value + "<br>");}// 获取context path (获取应用上下文的根)String contextPath = application.getContextPath();out.print(contextPath + "<br>");// 获取文件的绝对路径// 后面的这个路径,加了一个“/”,这个“/”代表的是web的根String realPath = application.getRealPath("/index.html"); // 可以// 你不加“/”,默认也是从根下开始找。String realPath2 = application.getRealPath("index.html"); // 不加“/”也可以out.print(realPath + "<br>");out.print(realPath2 + "<br>");// D:\javadaima-heji\javadaima4\out\artifacts\Servlet04_war_exploded\common\common.htmlString realPath3 = application.getRealPath("/common/common.html");out.print(realPath3 + "<br>");}
}

4.通过ServletContext对象也是可以记录日志的

// 通过ServletContext对象也是可以记录日志的
public void log(String message);
public void log(String message, Throwable t);
// 这些日志信息记录到哪里了?
// localhost.2021-11-05.log// Tomcat服务器的logs目录下都有哪些日志文件?
//catalina.2021-11-05.log 服务器端的java程序运行的控制台信息。
//localhost.2021-11-05.log ServletContext对象的log方法记录的日志信息存储到这个文件中。
//localhost_access_log.2021-11-05.txt 访问日志
package oop1;import jakarta.servlet.*;import javax.swing.text.GapContent;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;/*** ServletContext* 1. ServletContext是什么?*  ServletContext是接口,是Servlet规范中的一员。* 2. ServletContext是谁实现的?*  Tomcat服务器(WEB服务器)实现了ServletContext接口。*  public class org.apache.catalina.core.ApplicationContextFacade implements ServletContext {}* 3. ServletContext对象是谁创建的?在什么时候创建的?*  ServletContext对象在WEB服务器启动的时候创建。*  ServletContext对象是WEB服务器创建的。*  对于一个webapp来说,ServletContext对象只有一个。*  ServletContext对象在服务器关闭的时候销毁。* 4. ServletContext怎么理解?*  context是什么意思?*      Servlet对象的环境对象。(Servlet对象的上下文对象。)*  ServletContext对象其实对应的就是整个web.xml文件。*  50个学生,每个学生都是一个Servlet,这50个学生都在同一个教室当中。那么这个教室就相当于ServletContext对象。*  放在ServletContext对象当中的数据,所有Servlet一定是共享的。*  比如:一个教室中的空调是所有学生共享的,一个教室中的语文老师是所有学生共享的。*  Tomcat是一个容器,一个容器当中可以放多个webapp,一个webapp对应一个ServletContext对象。*/
public class AServlet extends GenericServlet {@Overridepublic void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {response.setContentType("text/html");PrintWriter out = response.getWriter();// 获取ServletContext对象ServletContext application = this.getServletContext();out.print("ServletContext对象是:" + application + "<br>");// 获取上下文的初始化参数Enumeration<String> initParameterNames = application.getInitParameterNames();while(initParameterNames.hasMoreElements()){String name = initParameterNames.nextElement();String value = application.getInitParameter(name);out.print(name + "=" + value + "<br>");}// 获取context path (获取应用上下文的根)String contextPath = application.getContextPath();out.print(contextPath + "<br>");// 获取文件的绝对路径// 后面的这个路径,加了一个“/”,这个“/”代表的是web的根String realPath = application.getRealPath("/index.html"); // 可以// 你不加“/”,默认也是从根下开始找。String realPath2 = application.getRealPath("index.html"); // 不加“/”也可以out.print(realPath + "<br>");out.print(realPath2 + "<br>");// D:\javadaima-heji\javadaima4\out\artifacts\Servlet04_war_exploded\common\common.htmlString realPath3 = application.getRealPath("/common/common.html");out.print(realPath3 + "<br>");// 通过ServletContext对象也是可以记录日志的// 这些日志信息记录到哪里了?application.log("你好,世界");application.log("快乐星期");}
}

5.存(怎么向ServletContext应用域中存数据)

// ServletContext对象还有另一个名字:应用域(后面还有其他域,例如:请求域、会话域)

// 如果所有的用户共享一份数据,并且这个数据很少的被修改,并且这个数据量很少,可以将这些数据放到ServletContext这个应用域中

// 为什么是所有用户共享的数据? 不是共享的没有意义。因为ServletContext这个对象只有一个。只有共享的数据放进去才有意义。

// 为什么数据量要小? 因为数据量比较大的话,太占用堆内存,并且这个对象的生命周期比较长,服务器关闭的时候,这个对象才会被销毁。大数据量会影响服务器的性能。占用内存较小的数据量可以考虑放进去。

// 为什么这些共享数据很少的修改,或者说几乎不修改?
// 所有用户共享的数据,如果涉及到修改操作,必然会存在线程并发所带来的安全问题。所以放在ServletContext对象中的数据一般都是只读的。

// 数据量小、所有用户共享、又不修改,这样的数据放到ServletContext这个应用域当中,会大大提升效率。因为应用域相当于一个缓存,放到缓存中的数据,下次在用的时候,不需要从数据库中再次获取,大大提升执行效率。

// 存(怎么向ServletContext应用域中存数据)
public void setAttribute(String name, Object value); // map.put(k, v)
// 取(怎么从ServletContext应用域中取数据)
public Object getAttribute(String name); // Object v = map.get(k)
// 删(怎么删除ServletContext应用域中的数据)
public void removeAttribute(String name); // map.remove(k)

user类:

package oop1;public class User {private String name;private String password;@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", password='" + password + '\'' +'}';}public User() {}public User(String name, String password) {this.name = name;this.password = password;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}
}

在AServlet中添加如下代码

    // 准备数据User user = new User("jack", "123");// 向ServletContext应用域当中存储数据application.setAttribute("userObj", user);// 取出来Object userObj = application.getAttribute("userObj");// 输出到浏览器out.print(userObj + "<br>");

运行结果:

可以在AServlet中只添加如下代码

 // 准备数据User user = new User("jack", "123");// 向ServletContext应用域当中存储数据application.setAttribute("userObj", user);

在BServlet中添加

    // 取出来Object userObj = application.getAttribute("userObj");// 输出到浏览器out.print(userObj + "<br>");

运行结果:

先刷b为null

注意以后我们编写Servlet类的时候,实际上是不会去直接继承GenericServlet类的,因为我们是B/S结构的系统,这种系统是基于HTTP超文本传输协议的,在Servlet规范当中,提供了一个类叫做HttpServlet,它是专门为HTTP协议准备的一个Servlet类。我们编写的Servlet类要继承HttpServlet。(HttpServlet是HTTP协议专用的。)使用HttpServlet处理HTTP协议更便捷。但是你需要直到它的继承结构:

jakarta.servlet.Servlet(接口)【爷爷】
jakarta.servlet.GenericServlet implements Servlet(抽象类)【儿子】
jakarta.servlet.http.HttpServlet extends GenericServlet(抽象类)【孙子】我们以后编写的Servlet要继承HttpServlet类。
  • 大家到目前为止都接触过哪些缓存机制了?

    • 堆内存当中的字符串常量池。

      • "abc" 先在字符串常量池中查找,如果有,直接拿来用。如果没有则新建,然后再放入字符串常量池。

    • 堆内存当中的整数型常量池。

      • [-128 ~ 127] 一共256个Integer类型的引用,放在整数型常量池中。没有超出这个范围的话,直接从常量池中取。

    • 连接池(Connection Cache)

      • 这里所说的连接池中的连接是java语言连接数据库的连接对象:java.sql.Connection对象。

      • JVM是一个进程。MySQL数据库是一个进程。进程和进程之间建立连接,打开通道是很费劲的。是很耗费资源的。怎么办?可以提前先创建好N个Connection连接对象,将连接对象放到一个集合当中,我们把这个放有Connection对象的集合称为连接池。每一次用户连接的时候不需要再新建连接对象,省去了新建的环节,直接从连接池中获取连接对象,大大提升访问效率。

      • 连接池

        • 最小连接数

        • 最大连接数

        • 连接池可以提高用户的访问效率。当然也可以保证数据库的安全性。

    • 线程池

      • Tomcat服务器本身就是支持多线程的。

      • Tomcat服务器是在用户发送一次请求,就新建一个Thread线程对象吗?

        • 当然不是,实际上是在Tomcat服务器启动的时候,会先创建好N多个线程Thread对象,然后将线程对象放到集合当中,称为线程池。用户发送请求过来之后,需要有一个对应的线程来处理这个请求,这个时候线程对象就会直接从线程池中拿,效率比较高。

        • 所有的WEB服务器,或者应用服务器,都是支持多线程的,都有线程池机制。

    • redis

      • NoSQL数据库。非关系型数据库。缓存数据库。

    • 向ServletContext应用域中存储数据,也等于是将数据存放到缓存cache当中了。

相关文章:

Servlet开发与生命周期详解-2

一、在集成开发环境当中开发Servlet程序 1.集成开发工具很多&#xff0c;其中目前使用比较多的是&#xff1a; IntelliJ IDEA&#xff08;这个居多&#xff0c;IDEA在提示功能方面要强于Eclipse&#xff0c;也就是说IDEA使用起来比Eclipse更加智能&#xff0c;更好用。JetBrai…...

vue2项目eslint提示<template v-for> key should be placed on the <template> tag

在template标签上使用v-for时&#xff0c;vue2会提示key不可放在template标签上&#xff0c;必须放在子元素上。vue3会提示key必须放在template标签上。这时候可能我们怎么写都会触发eslint校验提醒。不影响使用&#xff0c;但看着难受。 我们可以在根目录上新建jsconfig.json…...

老是忘记package.json,备忘一下 webpack 环境下 Vue Cli 和 Vite 命令行工具对比

Vue 2.X webpack 环境下 Vue Cli 的命令 "scripts": {"dev": "vue-cli-service serve","prod": "vue-cli-service serve --mode production","build:dev": "vue-cli-service build --mode development"…...

关于跨域问题(本地前端访问服务器端接口跨域出错)

问题来源&#xff1a; 当服务器封装了接口但是本地电脑端前端访问出现跨域问题。 解决方案&#xff1b; 1、使用ipconfig 查看本地电脑的ip地址 ipconfig 2、在后端接口处配置如下代码 allow_origins["http://本地ip地址:3001", # 局域网内其他设备访问的本地…...

Jackson相关问题

1、json转dto的时候&#xff0c;dto不能定义isActive这种带有is的前缀&#xff0c;如果使用Lombok的Getter/Setter的话&#xff0c;json {"isActive": true}&#xff0c;这样&#xff0c;将无法正确赋值。此时的dto再次转为json之后&#xff0c;得到的是active:false…...

【C++】互斥锁(Mutex)和原子操作(Atomics)

详细探讨 C 中的并发、多线程、互斥锁&#xff08;Mutex&#xff09;和原子操作&#xff08;Atomics&#xff09;的概念及其区别&#xff0c;并附带代码示例。 1. C 并发与多线程 (Concurrency vs. Multithreading) 并发 (Concurrency)&#xff1a;指系统能够处理多个任务的能…...

Linux--命令行操作

一、Linux的作用 1.简单的文件操作 2.编程 3.支持系统和网络 二、多账号管理 1、我们需要在root账号下进行&#xff0c;可以用whoami来查询账号身份 2、adduser 你要创建的账号名 就可以创建一个账号 3、ls /home可以查看账号是否创立 4、使用passwd 创建账号名字的来设…...

具身系列——Diffusion Policy算法实现CartPole游戏

代码原理分析 1. 核心思想 该代码实现了一个基于扩散模型&#xff08;Diffusion Model&#xff09;的强化学习策略网络。扩散模型通过逐步去噪过程生成动作&#xff0c;核心思想是&#xff1a; • 前向过程&#xff1a;通过T步逐渐将专家动作添加高斯噪声&#xff0c;最终变成…...

4.用 Excel 录入数据

一 用 Excel 录入数据的两种方式 用鼠标键盘录入数据和从网上爬取数据。 二 用鼠标键盘录入数据 1.录入数据的规范 横着录入数据&#xff08;横着一条条录入数据&#xff09;。 2.使用快捷键进行数据录入 tab 键和 enter 键。 tab 键&#xff1a;向右移动一个单元格。 tab 键…...

nginx配置跳转设置Host有误导致报404问题

我们有个项目&#xff0c;前端调用了第三方接口。为了避免跨域&#xff0c;所以使用nginx进行转发。一直正常工作&#xff0c;相安无事。近日第三方调整了安全策略&#xff0c;http转换成https&#xff0c;原本使用ip&#xff0c;现在也改成使用域名&#xff0c;所以nginx这里我…...

接口/UI自动化面试题

一、UI自动化 1.1、接口和UI自动化有多少用例&#xff1f; 回答策略&#xff1a;根据接口设定用例&#xff0c;100个接口&#xff0c;自动化case在1500-2000左右。结合自身的项目&#xff0c;回答覆盖的主功能流程。 示例&#xff1a; 接口自动化的测试case一般需要根据接口数…...

Java 中调用语言模型(如 OpenAI、阿里云通义千问、Hugging Face 等)API 的详细步骤和示例代码,涵盖常见场景及注意事项

以下是 Java 中调用语言模型&#xff08;如 OpenAI、阿里云通义千问、Hugging Face 等&#xff09;API 的详细步骤和示例代码&#xff0c;涵盖常见场景及注意事项&#xff1a; 1. 常见语言模型 API 选择 (1) OpenAI API 特点&#xff1a;支持 GPT-3、GPT-3.5、GPT-4 等模型&a…...

搜广推校招面经六十

soul推荐算法 一、word2vec原理 参考一篇文章入门Word2Vec 二、word2vec正负采样怎么做的、word2vec采用的loss和原理 见【搜广推校招面经四、搜广推校招面经五十二、搜广推校招面经五十七】 不太理解为啥问这么多word2vec&#xff0c;索性直接整理一遍。 三、多路召回融合…...

红宝书第十二讲:详解JavaScript中的工厂模式与原型模式等各种设计模式

红宝书第十二讲&#xff1a;详解JavaScript中的工厂模式与原型模式等各种设计模式 资料取自《JavaScript高级程序设计&#xff08;第5版&#xff09;》。 查看总目录&#xff1a;红宝书学习大纲 工厂模式和原型模式解析 一、工厂模式&#xff1a;像订外卖一样创建对象 工厂模…...

Flutter完整开发实战详解(一、Dart语言和Flutter基础)

前言 在如今的 Flutter 大潮下&#xff0c;本系列是让你看完会安心的文章。本系列将完整讲述&#xff1a;如何快速从0开发一个完整的 Flutter APP&#xff0c;配套高完成度 Flutter 开源项目 GSYGithubAppFlutter。同时也会提供一些 Flutter 的开发细节技巧&#xff0c;并针对…...

Kafka 偏移量

在 Apache Kafka 中&#xff0c;偏移量&#xff08;Offset&#xff09;是一个非常重要的概念。它不仅用于标识消息的位置&#xff0c;还在多种场景中发挥关键作用。本文将详细介绍 Kafka 偏移量的核心概念及其使用场景。 一、偏移量的核心概念 1. 定义 偏移量是一个非负整数…...

手撕LRU缓存Java版(带输入输出)

由于面试手撕lru没撕出来&#xff0c;导致心态炸裂&#xff0c;今天特地练习了lru输入输出 手撕版&#xff0c;在每个函数里手动加上输出 public class LC146 {static class LRUCache{class Node{int key, value;Node prev, next;Node(int key, int value){this.key key;thi…...

Android 12系统源码_系统启动(二)Zygote进程

前言 Zygote&#xff08;意为“受精卵”&#xff09;是 Android 系统中的一个核心进程&#xff0c;负责 孵化&#xff08;fork&#xff09;应用进程&#xff0c;以优化应用启动速度和内存占用。它是 Android 系统启动后第一个由 init 进程启动的 Java 进程&#xff0c;后续所有…...

python之并发编程

并发编程介绍 串行、并行与并发的区别 进程、线程、协程的区别 1. 进程 (Process) 定义&#xff1a;进程是操作系统为运行中的程序分配的基本单位。每个进程都有独立的地址空间和资源&#xff08;如内存、文件句柄等&#xff09;。特点&#xff1a; 进程是资源分配的基本单位…...

极速全场景 MPP数据库starrocks介绍

目录 一、引子 二、起源 &#xff08;一&#xff09;前身 &#xff08;二&#xff09;定位 三、特点 &#xff08;一&#xff09;高性能架构 &#xff08;二&#xff09;实时分析 &#xff08;三&#xff09;高并发与扩展性 &#xff08;四&#xff09;兼容性与生态 …...

MySQL 表连接(内连接与外连接)

&#x1f3dd;️专栏&#xff1a;Mysql_猫咪-9527的博客-CSDN博客 &#x1f305;主页&#xff1a;猫咪-9527-CSDN博客 “欲穷千里目&#xff0c;更上一层楼。会当凌绝顶&#xff0c;一览众山小。” 目录 1、表连接的核心概念 1.1 为什么需要表连接&#xff1f; 2、内连接&a…...

重学Java基础篇—什么是快速失败(fail-fast)和安全失败(fail-safe)?

快速失败&#xff08;fail-fast&#xff09; 和 安全失败&#xff08;fail-safe&#xff09; 是两种不同的迭代器设计策略&#xff0c;主要用于处理集合&#xff08;如 List、Map&#xff09;在遍历过程中被修改的场景。 它们的核心区别在于对并发修改的容忍度和实现机制。 1…...

Redis 集群配置

在币圈交易所&#xff0c;Redis 集群的节点数量和内存大小通常根据交易所的规模、访问量、并发需求等因素来决定。一般来说&#xff0c;可以按照以下标准配置&#xff1a; Redis 集群节点数量 小型交易所&#xff08;日活 < 10万&#xff0c;QPS < 10k&#xff09;&…...

容器C++

string容器 string构造函数 #include<iostream> using namespace std; #include<string.h> void test01() {string s1;//默认构造const char* str "hello world";string s2(str);//传入char*cout << "s2" << s2 << endl;s…...

Git 基础入门:从概念到实践的版本控制指南

一、Git 核心概念解析 1. 仓库&#xff08;Repository&#xff09; Git 的核心存储单元&#xff0c;包含项目所有文件及其完整历史记录。分为本地仓库&#xff08;开发者本地副本&#xff09;和远程仓库&#xff08;如 GitHub、GitLab 等云端存储&#xff09;&#xff0c;支持…...

蓝桥杯真题_小蓝和小桥的讨论

小蓝和小桥的讨论 问题描述 小蓝和小桥是一所高中的好朋友&#xff0c;他们正在讨论下一次的课程。这节课需要讨论 nn 个主题&#xff0c;第 ii 个主题对老师来说有 aia**i 的趣味度&#xff0c;对学生来说有 bib**i 的趣味度。 小蓝认为&#xff0c;如果一个主题对老师来说…...

【C++游戏引擎开发】《线性代数》(2):矩阵加减法与SIMD集成

一、矩阵加减法数学原理 1.1 定义 ​逐元素操作:运算仅针对相同位置的元素,不涉及矩阵乘法或行列变换。​交换律与结合律: 加法满足交换律(A + B = B + A)和结合律( ( A + B ) + C = A + ( B + C ) )。 ​减法不满足交换律(A − B ≠ B − A)。1.2 公式 ​ C i j = …...

HTML应用指南:利用POST请求获取全国小鹏汽车的充电桩位置信息

在新能源汽车快速发展的背景下&#xff0c;充电桩的分布和可用性成为影响用户体验的关键因素之一。随着全球对环境保护意识的增强以及政府对新能源政策的支持&#xff0c;越来越多的消费者倾向于选择电动汽车作为日常出行工具。然而&#xff0c;充电设施是否完备、便捷直接影响…...

工具介绍《WireShark》

Wireshark 过滤命令中符号含义详解 一、比较运算符 Wireshark 支持两种比较运算符语法&#xff1a;英文缩写&#xff08;如 eq&#xff09;和 C语言风格符号&#xff08;如 &#xff09;&#xff0c;两者功能等价。 符号&#xff08;英文缩写&#xff09;C语言风格符号含义示…...

深入理解 Linux 中磁盘空间驱动的编写:从原理到实践

在编写 Linux 内核中的磁盘空间驱动时&#xff0c;理解不同类型的存储设备及其在内核中的工作模式至关重要。常见的存储设备主要分为两类&#xff1a;采用 MTD&#xff08;Memory Technology Device&#xff09;模式的原始闪存设备&#xff08;如 NAND、NOR Flash&#xff09;&…...

flutter android端抓包工具

flutter做的android app&#xff0c;使用fiddler抓不了包&#xff0c;现介绍一款能支持flutter的抓包工具Reqable&#xff0c;使用方法如下&#xff1a; 1、下载电脑端安装包 下载地址为【https://reqable.com/zh-CN/download/】 2、还是在上述地址下载 android 端apk&#xf…...

知识周汇 | 用 matplotlib 轻松绘制折线图、散点图、柱状图、直方图

目录 前言 折线图 散点图 柱状图 直方图 组合图&#xff1a;柱状图和折线图 1. 导入库 2. 定义组合图函数 3. 设置中文字体和样式 4. 创建画布和子图 5. 绘制柱状图 6. 绘制折线图 7. 美化图表 8. 保存和显示图表 9. 调用函数 总结 前言 matplotlib 是 Python…...

Ribbon负载均衡的深度解析与应用

在微服务架构中&#xff0c;服务之间的调用频繁且复杂&#xff0c;因此负载均衡显得尤为重要。Spring Cloud生态系统中&#xff0c;Ribbon作为一个客户端负载均衡器&#xff0c;扮演着关键的角色。它不仅能提高系统的响应速度&#xff0c;还能确保系统的稳定性和可用性。接下来…...

Neo4j GDS-06-neo4j GDS 库中社区检测算法介绍

neo4j apoc 系列 Neo4j APOC-01-图数据库 apoc 插件介绍 Neo4j APOC-01-图数据库 apoc 插件安装 neo4j on windows10 Neo4j APOC-03-图数据库 apoc 实战使用使用 Neo4j APOC-04-图数据库 apoc 实战使用使用 apoc.path.spanningTree 最小生成树 Neo4j APOC-05-图数据库 apo…...

Android 删除aar中的一个类 aar包冲突 aar类冲突 删除aar中的一个包

Duplicate class com.xxxa.naviauto.sdk.listener.OnChangeListener found in modules jetified-xxxa-sdk-v1.1.2-release-runtime (:xxx-sdk-v1.1.2-release:) and jetified-xxxb-sdk-1.1.3-runtime (:xxxb-sdk-1.1.3:) A.aar B.aar 有类冲突&#xff1b; 使用 exclude 排除本…...

【老电脑翻新】华硕A456U(换电池+换固态+光驱换机械+重装系统+重装系统后开始菜单失灵问题解决)

前言 电脑华硕A456U买来快10年了&#xff0c;倒是还能用&#xff0c;就是比较卡&#xff0c;cpu占比总是100%&#xff0c;之前已经加过内存条了。想要不换个固态看看。 省流&#xff1a;没太大效果。 记录一下拆机&换固态的过程 准备 西部数据固态硬盘480G WD Green S…...

Unity 简单使用Addressables加载SpriteAtlas图集资源

思路很简单&#xff0c;传入图集名和资源名&#xff0c;利用Addressables提供的异步加载方式从ab包中加载。加载完成后存储进缓存字典里&#xff0c;以供后续使用。 添加引用计数&#xff0c;防止多个地方使用同一图集时&#xff0c;不会提前释放 using UnityEngine; using U…...

stable diffusion本地安装

1. 基本环境准备 安装conda 环境 pytorch基础学习-CSDN博客 创建虚拟环境&#xff1a; conda create -n sd python3.10 一定要指定用3.10&#xff0c;过高的版本会提示错误&#xff1a; 激活启用环境&#xff1a; conda activate sd 设置pip国内镜像源&#xff1a; pip conf…...

MQ 如何保证数据一致性?

大家好&#xff0c;我是苏三&#xff0c;又跟大家见面了。 前言 上个月&#xff0c;我们有个电商系统出了个灵异事件&#xff1a;用户支付成功了&#xff0c;但订单状态死活不改成“已发货”。 折腾了半天才定位到问题&#xff1a;订单服务的MQ消息&#xff0c;像人间蒸发一…...

spring @Autowired对属性、set方法,构造器的分别使用,以及配合 @Autowired 和 @Qualifier避免歧义性的综合使用案例

代码结构 依赖注入 在Spring IoC容器的概念中&#xff0c;主要是使用依赖注入来实现Bean之间的依赖关系的 举例 例如&#xff0c;人类&#xff08;Person&#xff09;有时候会利用动物&#xff08;Animal&#xff09;来完成一些事情&#xff0c;狗&#xff08;Dog&#xff0…...

Ubuntu 系统上完全卸载 Docker

以下是在 Ubuntu 系统上完全卸载 Docker 的分步指南 一.卸载验证 二.卸载步骤 1.停止 Docker 服务 sudo systemctl stop docker.socket sudo systemctl stop docker.service2.卸载 Docker 软件包 # 移除 Docker 核心组件 sudo apt-get purge -y \docker-ce \docker-ce-cli …...

国际机构Gartner发布2025年网络安全趋势

转自&#xff1a;中国新闻网 中新网北京3月14日电 国际机构高德纳(Gartner)14日发布的消息称&#xff0c;网络安全和风险管理在2025年“面临挑战与机遇并存的局面”&#xff0c;“实现转型和提高弹性”对确保企业在快速变化的数字世界中&#xff0c;实现安全且可持续的创新至关…...

设计秒杀系统(高并发的分布式系统)

学海无涯&#xff0c;志当存远。燃心砺志&#xff0c;奋进不辍。 愿诸君得此鸡汤&#xff0c;如沐春风&#xff0c;事业有成。 若觉此言甚善&#xff0c;烦请赐赞一枚&#xff0c;共励学途&#xff0c;同铸辉煌&#xff01; 思路 处理高并发 流量削峰&#xff1a;限流&#xf…...

C# 打印模板设计-ACTIVEX打印控件-多模板加载

一、启动软件 using System; using System.Collections.Generic; using System.Windows.Forms; using System.Data;namespace Print {static class Program{/// <summary>/// 应用程序的主入口点。/// </summary>[STAThread]static void Main(){//使用模板前必须…...

华为HCIE方向那么多应该如何选择?

在华为认证体系里&#xff0c;HCIE作为最高等级的认证&#xff0c;是ICT领域专业实力的有力象征。HCIE设置了多个细分方向&#xff0c;这些方向宛如不同的专业赛道&#xff0c;为期望在ICT行业深入发展的人提供了丰富的选择。今天&#xff0c;咱们就来好好聊聊华为HCIE方向的相…...

五子棋游戏

五子棋 - deveco <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>五子棋 - deveco</title>…...

Vue3.5 企业级管理系统实战(十):面包屑导航组件

1 breadcrumb 组件 1.1 安装插件 path-to-regexp 首先&#xff0c;我们需要安装插件 path-to-regexp&#xff0c;以便在下面的面包屑组件中对路由地址进行解析。 path-to-regexp是一个 JavaScript 库&#xff0c;可将路径字符串转化为正则表达式&#xff0c;广泛用于 Web 开发…...

【python】OpenCV—Hand Detection

文章目录 1、功能描述2、代码实现3、效果展示4、完整代码5、参考6、其它手部检测和手势识别的方案 更多有趣的代码示例&#xff0c;可参考【Programming】 1、功能描述 基于 opencv-python 和 mediapipe 进行手部检测 2、代码实现 导入必要的库函数 import cv2 import media…...

[ComfyUI] SDXL Prompt Styler 自定义节点的作用解析

1. SDXL Prompt Styler 的位置与基本功能 在 ComfyUI 的 “新建节点” → “实用工具” 下,可以找到 Style 节点(SDXL Prompt Styler)。该节点的主要作用是对输入的描述进行结构化处理,并在转换为 Stable Diffusion XL (SDXL) 提示词时,自动补充风格相关的内容,使提示词…...

Oracle-rman restore遭遇RMAN-03002与ORA-19563

文章目录 在原DB上检查是否有重复的文件名&#xff1a;查看rman恢复的日志修正重名部分重新执行rman恢复结论&#xff1a; 在 RMAN 恢复过程中&#xff0c;遇到RMAN-03002连同ORA-19563:错误。 操作是将 Oracle 10.0.5的数据库备份从 RMAN備份恢复到另一台测试主机的同一个目录…...