41 Servlet2 多线程

1 Java Servlet是和平台无关的服务器端组件,它运行在Servlet容器中。Servlet容器负责Servlet和客户的通信以及调用Servlet的方法,Servlet和客户的通信采用“请求/响应”的模式。
•Servlet可完成如下功能:
–创建并返回基于客户请求的动态HTML页面。
–创建可嵌入到现有 HTML 页面中的部分 HTML 页面(HTML 片段)。

–与其它服务器资源(如数据库或基于Java的应用程序)进行通信。


2 每一个Servlet都必须要实现Servlet接口,GenericServlet是个通用的、不特定于任何协议的Servlet,它实现了Servlet接口,而HttpServlet继承于GenericServlet,因此HttpServlet也实现了Servlet接口,所以我们定义的Servlet只需要继承HttpServlet父类即可。

3 Servlet接口中定义了一个service方法,HttpServlet对该方法进行了实现,实现方式就是将ServletRequest与ServletResponse转换为HttpServletRequest与HttpServletResponse

public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException {

        HttpServletRequest  request;
        HttpServletResponse response;
        
        try {
            request = (HttpServletRequest) req;
            response = (HttpServletResponse) res;
        } catch (ClassCastException e) {
            throw new ServletException("non-HTTP request or response");
        }
        service(request, response);
    }


4 转换完毕后,会调用HttpServlet类中自己定义的service方法,在该service方法中,首先获得到请求的方法名,然后根据方法名调用对应的doXXX方法,比如说请求方法为GET,那么就去调用doGet方法;请求方法为POST,那么就去调用doPost方法。

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 / 1000 * 1000)) {
                    // 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);
        }
    }


5在HttpServlet类中所提供的doGet、doPost等方法都是直接返回错误信息,所以我们需要在自己定义的Servlet类中override这些方法


protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {

        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_post_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
6 ServletRequest主要方法

•getAttribute 根据参数给定的属性名返回属性值
•getContentType 返回客户请求数据MIME类型
•getInputStream 返回以二进制方式直接读取客户请求数据的输入流
•getParameter 根据给定的参数名返回参数值
•getRemoteAddr 返回远程客户主机的IP地址(用于投票)
•getRemoteHost 返回远程客户主机名
•getRemotePort 返回远程客户主机的端口



7ServletResponse 主要方法

•getOutputStream 返回可以向客户端发送二进制数据的输出流对象ServletOutputStream
•getWriter 返回可以向客户端发送字符数据的PrintWriter对象
•getCharacterEncoding 返回Servlet发送的响应数据的字符编码
•getContentType 返回Servlet发送的响应数据的MIME类型
•setContentType 设置Servlet发送的响应数据的MIME类型


8 Servlet 何时被创建


默认情况下,当Web客户第一次请求访问某个Servlet时,Web容器创建这个Servlet的实例
•如果设置了<servlet>元素的<load-on-startup>子元素,Servlet容器在启动Web应用时,将按照指定的顺序创建并初始化这个Servlet。
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.test.servlet.HelloServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>


9某些Servlet在web.xml文件中只有<servlet>元素而没有<servlet-mapping>元素,这样我们就无法通过url地址的方式访问这个Servlet了,这种Servlet通常会在<servlet>元素中配置一个<load-on-startup>子元素,让容器在启动的时候自动加载该Servlet,并且调用其init方法完成一些全局性的初始化工作。


10 Servlet的多线程同步问题:Servlet本身是单实例的,这样当有多个用户同时访问某个Servlet时,会访问该唯一的Servlet实例中的成员变量,如果对成员变量进行写入操作,那就会导致Servlet的多线程问题,即数据不一致。

private String username;
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException
	{
		 username = req.getParameter("username");
		
		//得到当前线程的名字
		System.out.println(Thread.currentThread().getName());
		
		//进行一些后端的业务处理
		try
		{
			Thread.sleep(10000);
		}
		catch(Exception ex)
		{
			ex.printStackTrace();
		}
		
		req.setAttribute("username", username);
		req.getRequestDispatcher("hello.jsp").forward(req, resp);
	}

11 解决Servlet多线程同步问题的最好方案:去除实例变量,使用局部变量

12 JSP与Servelet

JSP的优点是擅长于网页制作,生成动态页面,比较直观。JSP的缺点是不容易跟踪与排错。
•Servlet是纯Java语言,擅长于处理流程和业务逻辑。Servlet的缺点是生成动态网页不直观。






















你可能感兴趣的:(41 Servlet2 多线程)