一、Servlet是什么
宏观地讲,Servlet是连接web服务器和服务端Java程序的协议,是一种通信规范,以一套接口的形式体现的。
通常来说,Servlet是宏观上Servlet规范中的一个具体接口,Servlet规范中包含一套接口,Servlet接口是其中之一。(在Java中存在于javax.servlet包中)
微观来讲,Servlet是Servlet接口实现类的一个实例对象,是运行在服务器上的一段Java小程序,即Server Applet。Servlet的主要功能是根据客户端提交的请求,调用服务端相关Java代码,完成对请求的处理和运算。
*Servlet接口中的方法
二、Servlet的注册
在创建了实现Servlet接口的类以后,Servlet在web.xml中注册。
1. Servlet实现类的注册:
2. 建立映射关系:
其中,一个Servlet可以有多个urlPattern与之匹配,
它的设置模式有以下几种:
(1)精确路径模式:如/here/some,请求路径和<url-pattern>的值完全相同才可被当前Servlet处理
(2)通配符路径模式:如/here/*,只要有/here/后面无论是什么都可被当前Servlet处理
(3)全路径模式:如/*,什么路径都可以匹配上,所有请求(包括所有动态资源和静态资源)通通拦截交给该Servlet处理;对于/,只能拦截静态资源,对于动态资源的请求(如jsp)不能被匹配上
(4)后缀名模式:如*.do,所有后缀名为do的请求都会被匹配上,一般是.do或者.action
它的匹配原则是:
(1)路径优先后缀匹配原则:同时匹配上路径和后缀名方式时,优先根据路径匹配Servlet
(2)精确路径优先匹配原则:同时匹配上几种路径时,优先以更精确(不带通配符)的路径匹配Servlet
(3)最长路优先匹配原则:同时匹配上几种带通配符/不带通配符的路径时,优先以更精切的路径匹配Servlet
三、Servlet的生命周期
Servlet整个生命周期过程的执行,均由web服务器负责管理(Servlet接口中实现的方法也只能由服务器调用),程序员无法控制器其流程。但是程序员可以获取到Servlet的生命周期时间点,并可以指定让Servlet做一些具体业务有关的事情。
当请求到达服务器,服务器会解析请求,解析出URI,解析出其中的ServletPath,并结合web.xml配置文件找到出对应的Servlet。
之后,若不存在该Servlet,会通过反射机制调用构造器构造,之后初始化;如果已经存在,直接调用service()方法进行服务调用。也就是说,Servlet的创建和初始化是在第一次访问对应的url时,之后的每次访问只需要只需要直接调用service()方法。
而且,Servlet是单例多线程的,在服务器中只有一个实例对象,可被多个浏览器访问。
在容器被关闭时,或者该应用被关闭时,调用destroy()方法,Servlet实例被销毁。
四、Servlet的特征
五、在web容器启动时就创建Servlet
由于Servlet的创建和初始化是在第一次访问对应的url时,所以对于第一个访问该url的用户来说,他等待的时间稍微长一点。为了提升用户体验,可以将一些常用Servlet在web容器启动时就创建。<load-on-startup>属性会让Servlet在容器启动时就被创建且被初始化。
其中<load-on-startup>之间必须是≥0的整数,其值代表了创建时的优先级。0的优先级最大。
六、创建Servlet的过程
1. 请求到达服务端,在第一个map中通过请求的url找到对应的Servlet引用,如果存在,调用该Servlet的service()方法;
2. 如果不存在,到第二个map中通过请求的url找到对应的Servlet全限定类名,通过反射机制(class.forName())创建一个该Servlet类的实例并且初始化;说明此时该Servlet还未创建,这是服务器启动后该URL第一次被访问
3. 把(url,新建的实例引用)放入第一个map中,并且调用该Servlet的service()方法;
七、ServletConfig
1. 什么是ServletConfig
可以从Servlet规范接口的init()方法中看到,服务器调用init方法时,会传入一个ServletConfig接口类型的参数。实际上,这个参数里面包含了Servlet的一些信息。但是我们不知道这个ServletConfig接口的实现类是谁,这就是协议的面向接口的抽象编程。
实际上,顾名思义,一个ServletConfig对象就对应了xml文件中注册的一个Servlet对象,它包含了这个Servlet对象的一些信息。
ServletConfig接口所包含的方法有如下几个:
(1)getInitParameter(String Name):获取以“name”为参数名称的参数的值。
(2)getInitParameterNames():返回一个String的枚举,是所有参数名字的枚举。
(3)getServletContext():获取Servlet上下文。
(4)getServletName():获取Servlet的名称。
2. 获取ServletConfig对象
可以发现Servlet另外提供了一个方法获取这个ServletConfig参数。
3. 通过ServletConfig获取Servlet的相关信息
获取到这个对象后,我们可以通过调用ServletConfig的一些方法来获取想得到的信息。
示例:
4. ServletContext的使用
通过ServletConfig可以获取一个名为ServletContext的属性。实际上,ServletContext中可以定义域属性和初始化参数,是与servlet对象无关的,是全局性的,可以在任意一个servlet中获取。
(1)初始化参数相关:getInitParameterNames()和getInitParameter(String Name)
在web.xml文件中,定义上下文初始化参数:
在代码中,可通过ServletContext获取:
启动服务器,在网页上访问该servlet对应的url,控制台输出:
(2)域属性相关:setAttribute(String Name, Object object)和removeAttribute(String Name)
在AServlet对象中设置域属性:
在BServlet中获取域属性:
启动服务器,在网页上访问BServlet对应的url,控制台输出:
之后,在BServlet中修改域属性:
启动服务器,在网页上访问BServlet对应的url,控制台输出:
(3)路径有关:getContextPath()和getRealPath(String path)
在控制台同样发现:
发现getContextPath()获取到的就是应用名称,而getRealPath(String path)是将URI转变为基于本地文件系统(file协议)下的文件路径。
七、只关注Servlet接口的service()方法
1. GenericServlet抽象类(缺省适配器设计模式)
如下所示:抽象类GenericServlet,包含了抽象方法service(),其余四个方法空实现。
在这之后,再想要定义Servlet相关类的时候,只需继承GenericServlet类,并且只需实现其中的service()方法即可。
也可以将比较上层的工作留在GenericServlet类中完成,比如ServletConfig的获取:
(1)GenericServlet类除了实现Servlet接口以外,还实现ServletConfig接口;
(2)在GenericServlet类中定义private ServletConfig sc,并且在init()和getServletConfig()中赋值给sc;
(3)实现ServletConfig接口的四个方法;
这样一来,在GenericServlet的子类中,只需要调用父类GenericServlet的这四个方法就可以获取ServletConfig里的相关信息,无需接触sc。
而在Servlet规范中,已经实现了GenericServlet类。