首页 > 其他分享 >Servlet

Servlet

时间:2023-01-07 10:08:26浏览次数:38  
标签:service Servlet 方法 void ServletConfig public

前言

  在微人事的项目中,我们看到了很多HttpServletRequest request, HttpServletResponse response作为参数传入到某个方法中,它通常作为HttpServlet中的service()方法传入参数;serveice()方法,它起源于Servlet接口,属于其中非常重要的一部分。

1.Servlet接口

  1.1 Tomcat的工作机制(重要)

  1. 客户端向Servlet容器(如Tomcat)发起Http请求,此时Servlet还未初始化
  2. Tomcat从磁盘中加载servlet,servlet加载成功
  3. Tomcat将Http请求封装为request对象,转发request给对应的Servlet处理
  4. Servlet将request处理为response返回给Tomcat,Tomcat将request转换成Http响应
  5. Tomcat将Http响应给客户端

  1.2 Servlet定义:

  1. 定义:java编写的应用成簇
  2. 功能:交互式地浏览和修改数据,生成动态web内容
  3. 狭义Servlet:实现了Servlet的接口
  4. 任何实现了Servlet接口的一个实现类

  1.3 Servlet的结构组成:

       Servlet接口、ServletRequest接口、ServletResponse接口、GenericServlet抽象类(实现了Servlet接口)、ServletContext接口、ServletConfig接口、ServletDispatcher接口、Filter接口

  1.4 Servlet的工作原理:

  1. Servlet容器将servlet加载到内存中,并产生servlet以及它能够调用的方法;在一个应用程序中,每个Servlet类型只能有一个Servlet对象
  2. 用户请求致使Servlet调用Servlet的service()方法,并传入一个ServletRequest和ServletResponse对象
  3. ServletRequest中封装了Http请求,无需技术人员解析原始Http数据,ServletResponse表示当前用户响应,程序员直接操作该对象返回响应给客户端用户
  4. 对任何一个应用程序,Servlet容器还会创建一个ServletConfig对象,该对象封装了应用程序的上下文环境,每个应用程序只有一个ServletConfig,每个Servlet对象只有一个Servlet配置的ServletConfig对象

  1.5 Servlet中的定义方法:

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

//返回Servlet容器传给init()方法的ServletConfig对象
Servlet getServletConfig();

void service(ServletRequest req, ServletResponse resp) throws ServletException{

}

String getServletInfo();

void destroy();
}

  1.6 Servlet的生命周期:

  1. 在上面的方法中,init()、sevice()、destroy()方法表示了Servlet对象出生到死亡的过程
  2. init()方法:当Servlet第一次被请求是,Servlet就会调用该方法,并传入一个ServletConfig对象初始化一个Servlet对象,在后续请求中,它不会再被调用
  3. service()方法:每当Servlet被请求是,Servlet就会调用该方法,init()只会被调用一次,而service像人生中的工作一样,一直工作知道去世
  4. destroy()方法:当要销毁Servlet时会调用该方法(卸载应用程序或关闭Serlvet容器),就会调用该方法,它也只会被调用一次

  1.7 GenericServlet抽象类:

   在实现Servlet的实现类中,我们都需要实现Servlet接口中的所有方法,及时不使用这些方法,而且还需要手动维护init()方法中ServletConfig对象的应用,这样显得很麻烦,GenericServlet抽象类应需而生,它实现了Servlet以及ServletConfig接口

Servlet_应用程序

Servlet_java_02

public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
private static final String LSTRING_FILE = "javax.servlet.LocalStrings";
private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.LocalStrings");
private transient ServletConfig config;

public GenericServlet() {
}

public void destroy() {
}

public String getInitParameter(String name) {
ServletConfig sc = this.getServletConfig();
if (sc == null) {
throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
} else {
return sc.getInitParameter(name);
}
}

public Enumeration<String> getInitParameterNames() {
ServletConfig sc = this.getServletConfig();
if (sc == null) {
throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
} else {
return sc.getInitParameterNames();
}
}

public ServletConfig getServletConfig() {
return this.config;
}

public ServletContext getServletContext() {
ServletConfig sc = this.getServletConfig();
if (sc == null) {
throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
} else {
return sc.getServletContext();
}
}

public String getServletInfo() {
return "";
}

public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}

public void init() throws ServletException {
}

public void log(String msg) {
this.getServletContext().log(this.getServletName() + ": " + msg);
}

public void log(String message, Throwable t) {
this.getServletContext().log(this.getServletName() + ": " + message, t);
}

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

public String getServletName() {
ServletConfig sc = this.getServletConfig();
if (sc == null) {
throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
} else {
return sc.getServletName();
}
}
}

GenericServlet抽象类

  GenericServlet中两个init()方法的作用

public void init(ServletConfig var1) throws ServletException{

}

public void init(ServletConfig config) throws ServletException{
this.config = config;
this.init();
}

  GenericServlet是一个抽象类无法产生实例,所以需要一个类继承它,就会出现覆盖的问题,如果实现该类就会覆盖该类的init()方法,那么程序员需要手动维护ServletConfig对象,这个不带参数的init()方法就是解决实现类覆盖问题的

2.javax.servlet.http

   HttpServlet之所比GenericServlet强大,是因为它是GenericServlet抽象类的扩展,并且它是与Http相结合的

  2.1 javax.servlet.http中的接口和类

    

Servlet_抽象类_03

  2.2 HttpServletRequest抽象类

   HttpSerlvet抽象类继承于GenericServlet抽象类,覆盖了该类service()方法,并添加了自己的service(HttpServletRequest request, HttpServletResponse response)方法

public void service(ServletRequest req, ServletResponse resp){
try{
HttpServlletRequest request;
HttpServletResponse response;
request = (HttpServletRequest)req;
response = (HttpServletResponse)resp;
}catch(ClassCastException e){ 
throw new ServletException("non-Http request or response");
} this.service(reques, response);
}

    上述代码中是直接将ServletRequest和ServletResponse对象转换为HttpServletRequest和HttpServletResponse对象,之所以这样转换是因为在调用Servlet的service方法时,

  Servlet容器(如Tomcat)总会出传入一份HttpServletRequest和HttpServletResponse对象,预备使用Http,因此转换不会出问题。

    转换之后,service()方法将来那个歌转换后的对象传入另一个service()方法,代码实现如下:

Servlet_应用程序

Servlet_java_02

public void service(HttpServletRequest req, HttpServletResponse resp){
String method = req.getMethod();
long lastNodified;
if(method.equals("GET")){
if(lastModified = -1){
this.doGet(req, resp);
}esle{
long ifModifiedSince = req.getDateHeader("If-Modified-Since");
if(ifModifiedSince < lastModified){
this.maybeSetLastModified(resp.lasrModified);
thi.doGet(req, resp);
}else{
rep.setStatus(304);
}
}else if(metyhod.equals("HEAD")){
lastModified = this.getLastModified(req);
this.maybeSetLastModified(resp, lastModified);
this.doHead(req, resp);
}else if(metyhod.equals("POST")){
this.doPost(req, resp);
}else if(metyhod.equals("PUT")){
this.doPut(req, resp);
}else if(metyhod.equals("DELETE")){
this.doDelete(req, resp);
}else if(metyhod.equals("OPTIONS")){
this.doOptions(req, resp);
}else if(metyhod.equals("TRACD")){
this.doTrace(req, resp);
}else{
String errMsg =
Strings.getString("http.method_not_implemented");
Object[] errArgs = new Object[]();
errMsg = MessageFormat.format(errMsg, errArgs);
resp.senError(501, errMsg);
}
}

另一个service()方法

    1.该service方法中没有任何的服务逻辑,但是会调用doGet、doPOST、doPut、doDelete、doOptions以及doTrace方法解析HttpServletRequest方法参数。其中最常用的就是doGet、doPOST方法

     2.具体的服务逻辑不需要service方法,而是重写doGet()和doPost()方法

  2.3 PrintWriter和ServletOutputStream获取字符流

    1.PrintWriter类的getWrite(String s )方法的write()方法将字符串设置到response缓存区。Tomcat将缓存区中的内容组装成Http响应返回给浏览器端

    2.ServletOutputStream类的getOutputStream()的write(byte[] bytes)想response缓存区写入字节,再有Tomcat将字节内容组装成Http响应返回给浏览器

    3.注意点:上面两类都可以发送响应消息体,但是他们之间相互排斥,不可以同时使用,否则会报异常

  2.4 Response乱码问题

    response乱码问题主要是两个部分,第一个response缓冲区默认编码是ISO-8859-1,不支持中文编码,修改为utf-8编码;第二个就是浏览器默认编码是GB2312也不支持中文编码,故要告诉浏览器所用utf-8编码

//1.response缓冲区编码方式为utf-8
response.setCharacterEncoding("utf-8");
//2.通知浏览器解码方式为utf-8
response.setHeader("Content-Type", "text/html;charset=utf-8");
//综合以上两种的response设置
response.setContentType("text/html;charset=utf-8");


3.ServletContextListener

  3.1 ServletContextListener

    ServletContextListener是一个监听ServletContext的接口,只要实现该类就可以实现“监听ServletContext”的功能

    

public interface ServletContextListener extends EventListener{
//1.ServletContext初始化(应用启动时)
void contextIninialized(ServletContextEvent var1);

//2.ServletContext销毁(应用停止)
void contextDestroy(ServletContextEvent var1);
}

  ServletContextListener工作流程:

  1. 应用程序启动时,ServletContext初始化,Servlet容器自动调用监听的ServletContextListener的contextInitializable(ServletContextEvent var1)方法,你并传入一个ServletContextEvent对象;
  2. 应用程序停止后,ServletContext销毁,Servlet容器调用该类的servletContextDestroy(ServletContextEvent var1)方法,并传入一个ServletContextEvent对象;

  3.2 ServletContextListener中应用

    ServletContext是一个“域对象”,存在在整个应用中,独此一份,它表示了当前应用的状态。

    

Servlet_应用程序

Servlet_java_02

//ContextLoaderListener是ServletContextListener在Spring中的应用
package org.springframework.web.context;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class ContextLoaderListener extends ContextLoader implements ServletContextLis
tener{
public ContextLoaderListener(){

}
public ContextLoaderListener(WebApplicationContext context){
super(context);
}
//重点
public void contextInitialized(ServletContextEvent event){
//ServletContextListener接口并没有这个方法
//所以查看该方法源码,观察它是如何实现spring实例化的
this.initWebApplicationContext(event.getServletContext());
}
public void contextDestroyed(ServleyContextEvent event){
this.closeWebApplicationContext(envent.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
}

spring中的ServletContextListener实现

    InitWebApplicationContext()方法源码,分析是如何进行Spring容器实例化

Servlet_应用程序

Servlet_java_02

public WebApplicationConetxt initWebApplicationContext(ServletContext servletContext){
if(servletContext.getAttribute(WebApplication.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null){
throw new IllegalStateException("Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml!");
}else{
Log logger = LogFactory.getLog(ContextLoader.class);
servletContext.log("Initializing Spring root WebApplicationContext");
if(logger.isInfoEnabled()){
logger.info("Root WebApplicationContext:initialization stared");
}
long startTime = System.curentTimeMills();
try{
if(this.context == null){
this.context = this.createWebApplicationContext(servletContext);
}
if(this.context instanceof ConfigurableWepApplicationContext){
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)this.context;
if(!cwac.isActive()){
if(cwac.getParent() == null){
ApplicationContext parent = this.loadParentContext(servletContext);
cwac.setParent(parent);
}
this.configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
//重点
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTIBUTE, this.context);
ClassLoader ccl = Thread.curerntThread().getContextClassLoader();
if(ccl == ContextLoader.class.getClassLoader()){
curerntContext = this.context;
}else if(ccl != null){
currentContextPerThread.put(ccl, this.context);
}
if (logger.isDebugEnabled()) {
logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
}
if (logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
}
return this.context;
}catch(RuntimeException var8){
logger.error("Context initialization failed", var8);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, var8);
throw var8;
}catch(Error var9){
logger.error("Context initialization failed", var9);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, var9);
throw var9;
}

源码实现

    代码分析

  1. 首先判断Servlet中是否存在WebApplication.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE标识,如果存在抛出IllegalStateException
  2. 如果为空,根据createWebApplicationContext()方法,并传入ServletContext对象默认实例化一个root容器;
  3. 根据loadParentContext()方法为root容器设置父上下文(父一般设置为0);
  4. 再根据configureAndRefreshWebApplicationContex()方法传入ConfigurableWebApplicationContext对象和servletContext对象配置容器并刷新
  5. 通过servletContext.setAttribute()方法,并传入WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTIBUTE, this.context来注册标识,并保存在当前线程中  

  3.3 ServletContextListener在Spring中应用流程

  1. Servlet容器启动时,ServletContext对象被初始化,然后Servlet容器调用配置文件中注册的监听该类的ServletContextListener类的contextInitialized(ServletContextEvent var1)方法,在该监听器中的调用this.InitWebApplicationContext()方法实例化spring IOC容器即ApplicationContext对象;
  2. 当ServletContext对象创建时,就可以创建ApplicationContext对象,当前者被销毁时,后者也可以被销毁,它们共生死


 



标签:service,Servlet,方法,void,ServletConfig,public
From: https://blog.51cto.com/u_15839058/5995370

相关文章

  • 动态网页技术-Servlet(2)
    1.Tomcat、Servlet与Http协议最终tomcat将http请求进行对应的响应,动态资源部分由servlet来实现,servlet在底层维护hashmap数组<k,v>键值对的形式,需要web.xml文件中的内容,最......
  • Servlet生成验证码
    Servlet生成验证码重写doGet和doPost方法1. java代码//图片高度privatestaticfinalintIMG_HEIGHT=100;//图片宽度private......
  • Servlet重定向
    Servlet重定向/转发就一行代码resp.sendRedirect("/response/image");//也可以跳转去jsp文件resp.sendRedirect("/response/success.jsp");不过要注意添加项目名,不......
  • 在创建servlet的时候可以直接通过下面的方式创建
    但是这样创建的servlet注解里面的内容是默认的,我们需要去设置里面去修改:......
  • 简单java servlet的登录脚本,部署到docker
    先打算参考这篇文章Simpleloginpageexampleusingjspservlet-Candidjava内含war文件和zip文件。但是tomcat上该war文件总是报错。于是又参考这篇(46条消息)Jav......
  • 学习笔记——过滤器链;监听器;Servlet、Filter、Listener的注解方式开发
    2023-01-06一、过滤器链1、含义:如果出现一个请求存在多个过滤器对其过滤,出现过滤器链。在放行前,过滤器是正序执行,放行后过滤器是倒序执行。2、过滤器的顺序:是与filter-......
  • Servlet
    1 Servlet 异常处理当一个Servlet抛出一个异常时,Web容器在使用了exception-type元素的 web.xml 中搜索与抛出异常类型相匹配的配置。您必须在web.xml中使用......
  • Servlet1
    1 Servlet 客户端HTTP请求当浏览器请求网页时,它会向Web服务器发送特定信息,这些信息不能被直接读取,因为这些信息是作为HTTP请求的头的一部分进行传输的。您可以查......
  • Servlet2
    1 Servlet 简介Servlet是什么?JavaServlet是运行在Web服务器或应用服务器上的程序,它是作为来自Web浏览器或其他HTTP客户端的请求和HTTP服务器上的数据库或......
  • Filter与Servlet的区别与联系
    在我们写代码时,在web.xml中总能发现类似下面的代码:<spanstyle="font-family:KaiTi_GB2312;font-size:18px;"><spanstyle="font-family:KaiTi_GB2312;font-size:18px;"......