Servlet学习


1介绍:

servlet 是用Java编写的服务器端程序。其主要功能在于交互式地浏览和修改数据,生成动态Web内容。

Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。


2引入包:

最新的servlet已经升级到3.0版本了。在应用过程中,通过maven引入即可。

<dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
</dependency>

3 生命周期:

Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:

  • Servlet 通过调用 init () 方法进行初始化。
  • Servlet 调用 service() 方法来处理客户端的请求。
  • Servlet 通过调用 destroy() 方法终止(结束)。
  • 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
在web容器中,servlet是属于单例型,即只创建一次。

在初始时调用init方法:public void init(ServletConfig config) throws ServletException; 此时通过ServletConfig读取相关配置参数。

初始化中也分为几种情况:

  • Servlet容器启动时自动装载某些Servlet,实现它只需要在web.XML文件中的<Servlet></Servlet>之间添加如下代码:<loadon-startup></loadon-startup>。
  • 在Servlet容器启动后,客户首次向Servlet发送请求
  • Servlet类文件被更新后,重新装载Servlet

Servlet被装载后,Servlet容器创建一个Servlet实例并且调用Servlet的init()方法进行初始化。在Servlet的整个生命周期内,init()方法只被调用一次。


每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务(servlet是单一的)。进入service方法执行: public void service(ServletRequest req, ServletResponse res)    throws ServletException, IOException; 如果是HttpServlet类,通过对请求的类型是GET还是POST等,再进入对应的方法:


@Override
    public 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");
        }

        request = (HttpServletRequest) req;
        response = (HttpServletResponse) res;

        service(request, response);
    }

注意,传入参数ServletRequest req, ServletResponse res  在转换成HttpServletRequest,HttpServletResponse后,调用此类型的service方法。我们再看下这个方式的实现内容:

 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方法,继承HttpServlet,重新定义doPost/doGet方法即可。

最后一个就是destroy方法了,destroy方法在容器移除servlet 时执行,同样只执行一次。这个方法会在所有的线程的service()方法执行完成或者超时后执行,调用这个方法后,容器不会再调用这个servlet的方法,也就是说容器不再把请求发送给这个servlet。这个方法给servlet释放占用的资源的机会,列如释放内存、文件句柄、线程等。

4 使用:

实际应用中,基本上有3类:直接实现Servlet接口、继承GenericServlet类、或继承HttpServlet类。其中一般servlet推荐使用Genericservlet,如果是在web中使用HttpServlet,它提供针对http的特殊实现的。

import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;

@WebServlet(name="annotationServlet", urlPatterns={"*.an"}, initParams={
        @WebInitParam(name="openFlag", value="true")
})
public class AnnotationServlet extends HttpServlet {

    
    private boolean openFlag = false;
    
    private int count = 0;
    
    /**
     * @Fields serialVersionUID : TODO
     */
    private static final long serialVersionUID = 1L;

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        count ++;
        
        System.out.println("AnnotationServlet --- service  openFlag = " + openFlag + " count = " + count+"; AnnotationServlet hashcode:" + this.getServletInfo().hashCode());
        
        super.service(req, resp);
    }

    @Override
    public void destroy() {
        System.out.println("AnnotationServlet --- destroy");
        super.destroy();
    }
    
    

    @Override
    public void init(ServletConfig config) throws ServletException {
        // TODO Auto-generated method stub
        super.init(config);
        
        String openFlag = config.getInitParameter("openFlag");
        this.openFlag = StringUtils.equals(openFlag, "true");
        
        System.out.println("AnnotationServlet --- init" +"; AnnotationServlet hashcode:" + this.getServletInfo().hashCode());
    }
}
---------------------------------------------------------------
import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LoadOnStartUpServlet extends HttpServlet {

    /**
     * @Fields serialVersionUID : TODO
     */
    private static final long serialVersionUID = 1L;
    
    private int count = 0;

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        
        System.out.println("LoadOnStartUpServlet---service :  count="+count+";LoadOnStartUpServlet hashcode:" + this.getServletInfo().hashCode());
        
        super.service(req, resp);
    }

    @Override
    public void destroy() {
        System.out.println("LoadOnStartUpServlet---destroy");
        super.destroy();
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println("LoadOnStartUpServlet---init" +"; LoadOnStartUpServlet hashcode:" + this.getServletInfo().hashCode());
        super.init(config);
    }
}


--------------------------------------------------------------------------------------

import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class XmlServlet extends HttpServlet {

    /**
     * @Fields serialVersionUID : TODO
     */
    private static final long serialVersionUID = 1L;
    
    private int count = 0;

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        
        System.out.println("XmlServlet---service :  count="+count+"; XmlServlet hashcode:" + this.getServletInfo().hashCode());
        
        super.service(req, resp);
    }

    @Override
    public void destroy() {
        System.out.println("XmlServlet---destroy");
        super.destroy();
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println("XmlServlet---init"+"; XmlServlet hashcode:" + this.getServletInfo().hashCode());
        super.init(config);
    }
}


web.xml配置:

 <servlet>
           <servlet-name>loadOnStartUpServlet</servlet-name>
           <servlet-class>com.zcl.servlet.LoadOnStartUpServlet</servlet-class>
           <load-on-startup>2</load-on-startup>
       </servlet>
       
       <servlet>
           <servlet-name>xmlServlet</servlet-name>
           <servlet-class>com.zcl.servlet.XmlServlet</servlet-class>
       </servlet>


<servlet-mapping>
           <servlet-name>xmlServlet</servlet-name>
           <url-pattern>*.xs</url-pattern>
       </servlet-mapping>
       
       <servlet-mapping>
           <servlet-name>loadOnStartUpServlet</servlet-name>
           <url-pattern>*.lon</url-pattern>
       </servlet-mapping>


以上定义了3个自定义的servlet,一个是web容器启动时就记载的loadOnStartUpServlet;一个是有请求过来时才创建的xmlServlet;一个也是有请求过来才创建的,但是使用注解方式的AnnotationServlet(在servlet3.*时提供的注解方式)。

运行时就可以看到他们的生命周期的过程。

5 异常处理:

当一个 Servlet 抛出一个异常时,Web 容器在使用了 exception-type 元素的 web.xml 中搜索与抛出异常类型相匹配的配置。

您必须在 web.xml 中使用 error-page 元素来指定对特定异常 或 HTTP状态码 作出相应的 Servlet 调用。

<error-page>
           <error-code>405</error-code>
           <location>/error.jsp</location>
</error-page>
       
<error-page>
           <exception-type>java.lang.Throwable</exception-type>
           <location>/error.jsp</location>
</error-page>




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值