Servlet接口
什么是Servlet?
Servlet是一种基于Java技术的Web组件,用于生成动静内容,由容器治理,是平台无关的Java类组成,并且由Java Web服务器加载执行,是Web容器的最根本组成单元
什么是Servlet容器?
Servlet容器作为Web服务器或应用服务器的一部分,通过申请和响应提供Web客户端与Servlets交互的能力,容器治理Servlet实例以及它们的生命周期(创立、初始化、提供服务、销毁等)
在java web中不论是应用J2EE原生的servlet/jsp还是应用springmvc/springboot,在web服务器看来只是对外裸露进去的Servlet,而这个Servlet是javax.servlet.Servlet接口,该接口定义了Servlet引擎与Servlet程序之间通信的协定约定。
// Servlet的加载和实例化能够产生在容器启动时,也能够提早初始化直到有申请须要解决时public interface Servlet { // 负责初始化Servlet对象,容器创立好Servlet对象后由容器调用调用,只执行一次 // 当load-on-startup设置为正数或者不设置时会在Servlet第一次用到时才被调用 void init(ServletConfig config) throws ServletException; // 获取该Servlet的初始化参数信息 ServletConfig getServletConfig(); // 负责响应客户端的申请,当容器接管到客户端要求拜访特定Servlet对象的申请时,会调用该Servlet对象的service()办法,每次申请都会执行 void service(ServletRequest req, ServletResponse res) throws ServletException, IOException; // 返回Servlet信息,蕴含创建者、版本、版权等信息 String getServletInfo(); // Servlet完结生命周期时调用,开释Servlet对象占用的资源 void destroy();}
<!-- more -->
而为了简化开发,jdk中提供了一个实现Servlet接口的简略的Servlet类,javax.servlet.GenericServlet,该类实现了Servlet的基本功能,对init(ServletConfig config)、service(ServletRequest req, ServletResponse res)和destroy()办法提供了默认实现
jdk针对HTTP协定专门提供了一个Servlet类,javax.servlet.http.HttpServlet,该类继承于GenericServlet类,在其根底上针对HTTP的特点进行裁减,个别编写程序时继承HttpServlet即可,这样只须要重写doGet()和doPost()办法即可
Servlet中波及的次要对象
- 申请对象 ServletRequest、HttpServletRequest
- 响应对象 ServletResponse、HttpServletResponse
- Servlet配置对象 ServletConfig
- Servlet上下文对象 ServletConfig
Servlet注册与运行
Servlet编写好之后须要在web.xml中进行注册和映射能力被Servlet容器加载从而被外界拜访
<!-- 留神servlet和servlet-mapping都是成对呈现的 --> <!-- 注册Servlet --> <servlet> <servlet-name>HW</servlet-name> <servlet-class>com.zhanghe.study.servlet.HelloWorldServlet</servlet-class> <!-- 配置servlet初始化init时中ServletConfig参数--> <init-param> <param-name>name</param-name> <param-value>john</param-value> </init-param> <!-- servlet加载机会,若为正数,则在第一次申请时被创立,若为0或者负数,在web利用被Servlet容器加载时创立实例,值越小越早被启动 --> <load-on-startup>1</load-on-startup> </servlet> <!-- 映射Servlet --> <servlet-mapping> <!-- 对应servlet标签中的servlet-name值 --> <servlet-name>HW</servlet-name> <!-- 结尾的/示意web用用程序的根目录 --> <url-pattern>/HelloWorld</url-pattern> </servlet-mapping>
tomcat中的web.xml蕴含有一个缺省的Servlet
<servlet> <servlet-name>default</servlet-name> <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>listings</param-name> <param-value>false</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
ServletConfig
对于每个Servlet可能在启动时都须要一些初始化参数,而所有的Servlet是交由Servlet引擎去实例化的,那么也就是须要将每个Servlet的初始化参数也都配置到web.xml中,Servlet引擎将Servlet容器对象和Servlet的配置信息封装到ServletConfig中,并在Servlet初始化时将ServletConfig传递给该Servlet。javax.servlet.ServletConfig接口的作用就是用来定义ServletConfig对象所须要对外提供的办法
public interface ServletConfig { // 获取web.xml中定义的servlet-name String getServletName(); // ServletContext示意的是利用自身 ServletContext getServletContext(); // 获取init-param配置的参数 String getInitParameter(String name); // 获取init-param配置的所有参数 Enumeration<String> getInitParameterNames();}
Servlet引擎装载并创立一个Servlet对象后,会调用该对象的init(ServletConfig config)办法,Servlet中的ServletConfig getServletConfig()办法会返回init传入的ServletConfig对象
<servlet> <servlet-name>HW</servlet-name> <servlet-class>com.zhanghe.study.servlet.HelloWorldServlet</servlet-class> <init-param> <param-name>name</param-name> <param-value>zhanghe</param-value> </init-param> </servlet>
// 获取指定的属性config.getInitParameter("name")// 获取所有的属性config.getInitParameters()
ServletContext
每个Web应用程序在启动时都会创立一个ServletContext对象,每个Web应用程序都有一个惟一的ServletContext对象,javax.servlet.ServletContext接口定义了ServletContext须要对外提供的办法,Servlet通过这些办法来和ServletContext容器进行通信
- 该对象代表以后WEB利用,能够获取到web利用的信息,一个Web利用只有一个ServletContext对象
- 能够应用ServletConfig的getServletContext()获取到ServletContext
- 能够获取web利用的初始化参数,这是全局的办法,在web.xml中配置<context-param>
- 获取web利用某个文件的绝对路径(在服务器上的门路,不是部署前的办法) getRealPath
- 获取以后利用的名称 getContextPath
- 获取以后web利用的某一个文件对应的输出流 getResourceAsStream() path是绝对于以后web利用的根目录
<context-param> <param-name>email</param-name> <param-value>master@163.com</param-value> </context-param>
servlet生命周期
生命周期相干办法,servlet生命周期中的办法全是由servlet容器来调用的
- 结构器 web容器调用Servlet的无参结构器,默认是在第一次申请时被加载,能够通过load-on-startup标签来进行设置什么时候加载
- init办法
- service办法
- destory办法
init办法--初始化
init办法在第一次创立servlet时被调用,在后续每次申请时都不会被调用。
当用户调用servlet的时候,该servlet的一个实例就会被创立,并且为每一个用户产生一个新的线程,init()用于进行一些初始化数据的加载和解决,这些数据会被用于servlet的整个生命周期
void init(ServletConfig config) throws ServletException;
为了避免重写该办法时开发者遗记将入参config赋值给成员变量config,故而提供了GenericServlet类进行了一次封装
public void init(ServletConfig config) throws ServletException { this.config = config; this.init();}
在进行Servlet重写时只须要重写不带参数的init办法即可
public void init() throws ServletException
该办法是由servlet容器调用的
什么时候触发初始化
有两种状况会进行Servlet的初始化
- Servlet被客户端首次申请拜访时触发初始化办法
如果配置了load-on-startup元素,则在Servlet容器启动该Servlet所属Web利用时就会初始化该Servlet
<servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet>
重写init办法
GenericServlet实现了Servlet和ServletConfig,是一个抽象类,并对init(ServletConfig var1)办法进行了一层封装,有一个ServletConfig成员变量,在init()办法中进行了初始化,使得能够间接在GenericServlet中间接应用ServletConfig办法
而咱们平时写Servlet大多是继承于HttpServlet类的,在对init办法进行重写时,重写不带参的init()办法即可
//GenericServlet类public void init(ServletConfig config) throws ServletException { this.config = config; this.init();}public void init() throws ServletException {}
该办法由GenericServlet的调用,如果须要应用到ServletConfig则调用getServletConfig()办法来获取
service办法
service办法是理论解决申请的办法,servlet容器调用service办法来解决申请,并将响应写回到客户端,每次服务器接管到一个新的servlet申请时,服务器会产生一个新的线程来调用服务
void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
解决申请逻辑
HttpServlet继承了GenericServlet,重写了service办法,将ServletRequest和ServletResponse转换为HttpServletRequest和HttpServletResponse,并依据不同的申请形式进行散发,doGet/doPost/doHead等
@Overridepublic void service(ServletRequest req, ServletResponse res) throws ServletException, IOException{ HttpServletRequest request; HttpServletResponse response; // 如果申请类型不相符,则抛出异样 if (!(req instanceof HttpServletRequest && res instanceof HttpServletResponse)) { throw new ServletException("non-HTTP request or response"); } // 转换成Http的request和response request = (HttpServletRequest) req; response = (HttpServletResponse) res; // 进行http的解决办法 service(request, response);}protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获取申请类型 String method = req.getMethod(); // 依据不同的申请类型调用不同的办法 if (method.equals(METHOD_GET)) { long lastModified = getLastModified(req); if (lastModified == -1) { // servlet doesn't support if-modified-since, no reason // to go through further expensive logic doGet(req, resp); } else { long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); if (ifModifiedSince < lastModified) { // If the servlet mod time is later, call doGet() // Round down to the nearest second for a proper compare // A ifModifiedSince of -1 will always be less maybeSetLastModified(resp, lastModified); doGet(req, resp); } else { resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } } } else if (method.equals(METHOD_HEAD)) { long lastModified = getLastModified(req); maybeSetLastModified(resp, lastModified); doHead(req, resp); } else if (method.equals(METHOD_POST)) { doPost(req, resp); } else if (method.equals(METHOD_PUT)) { doPut(req, resp); } else if (method.equals(METHOD_DELETE)) { doDelete(req, resp); } else if (method.equals(METHOD_OPTIONS)) { doOptions(req,resp); } else if (method.equals(METHOD_TRACE)) { doTrace(req,resp); } else { // // Note that this means NO servlet supports whatever // method was requested, anywhere on this server. // String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[1]; errArgs[0] = method; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); } }
servlet能够在任何协定下拜访 ,写的Servlet必须实现Servlet接口,在http协定下能够应用HttpServlet ,用来给Web拜访的
在HttpServlet类中对于service()办法进行了解决,依据申请形式的不同,将申请散发到了不同的办法,而咱们个别状况下写Servlet也是继承自HttpServlet的,所以在写申请解决逻辑时,只须要重写doGet()和doPost()办法即可
// HttpServlet类protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String msg = lStrings.getString("http.method_get_not_supported"); this.sendMethodNotAllowed(req, resp, msg);}protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String msg = lStrings.getString("http.method_post_not_supported"); this.sendMethodNotAllowed(req, resp, msg);}
GET办法
GET办法时浏览器向web服务器传递信息的默认办法,会在地址栏上产生很长的字符串,且GET办法有大小限度,申请字符串中最多只能有1024个字符
POST办法
POST办法不将申请信息放到地址中
destroy办法
destory()办法只在servlet生命周期完结时被调用一次。能够在destory()办法中进行一些资源的清理,如敞开数据库连贯、进行后盾线程等
https://zhhll.icu/2021/javaweb/根底/1.Servlet接口/
本文由mdnice多平台公布