zoukankan      html  css  js  c++  java
  • JavaWeb总结(一)—Servlet

    一、Servlet生命周期

    1.Servlet生命周期

      Serlet加载---->实例化---->服务---->销毁

    2.init()

    Servlet容器启动时:读取web.xml配置文件中的信息,构造指定的Servlet对象,创建ServletConfig对象,同时将ServletConfig对象作为参数来调用Servlet对象的init方法。

    Servlet容器启动后:客户首次向Servlet发出请求,Servlet容器会判断内存中是否存在指定的Servlet对象,如果没有则创建它,然后根据客户的请求创建HttpRequest、HttpResponse对象,从而调用Servlet 对象的service方法。

         在Servlet生命周期中,仅执行一次init()方法,它是在服务器装入Servlet时执行的,负责初始化Servlet对象。可以配置服务器或客户端首次访问Servlet时装入Servlet。无论有多少客户端访问Servlet,都不会重复执行init()方法。

    	@Override
    	public void init(ServletConfig config) throws ServletException{
    		// TODO Auto-generated method stub
    		super.init(config);
    	}

    3.service()

       它是Servlet的核心,负责响应客户的请求。每当一个客户端请求一个HttpServlet对象时,该对象的service()方法就会调用,而且传递给这个方法一个请求对象HttpServletRequest和响应对象HttpServletResponse对象作为参数。在HttpServlet中已复写了service()方法,该方法会自动判断用户的请求方式而执行不同的doXX()方法。

       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;
                    try {
                        ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                    } catch (IllegalArgumentException iae) {
                        // Invalid date header - proceed as if none was set
                        ifModifiedSince = -1;
                    }
                    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);
            }
        }

    4.destroy()

       仅执行一次,在服务端卸载Servlet时执行该方法。当Servlet对象退出生命周期时,负责释放占用的资源。一个Servlet在运行service()方法时会产生其他线程,因此需要确认在调用destroy()时,这些线程终止或完成。

    下面是流程图:

    clip_image002[7]

    步骤:

    (1)客户端向Servlet容器发出Http请求。

    (2)Servlet容器接收客户端的请求。

    (3)Servlet容器创建一个HttpServletRequest对象,将客户端请求的信息封装到这个对象中。

    (4)Servlet容器创建一个HttpServletResponse对象。

    (5)Servlet容器调用HttpServlet对象的service()方法,把HttpServletRequest对象与HttpServletResponse对象作为参数传给 HttpServlet 对象。

    (6)HttpServlet调用HttpServletRequest对象的有关方法,获取Http请求信息。

    (7)HttpServlet调用HttpServletResponse对象的有关方法,生成响应数据。

    (8)Servlet容器把HttpServlet的响应结果传给客户端。

    注意:

    (1)load-on-startupweb.xml中的含义

       在servlet的配置当中,<load-on-startup>1</load-on-startup>的含义是:标记容器是否在启动的时候就加载这个servlet。

       当值为0或者大于0时,表示容器在应用启动时就加载这个servlet;当是一个负数时或者没有指定时,则指示容器在该servlet被选择时才加载。正数的值越小,启动该servlet的优先级越高。

       为什么不是true和false呢?这是因为如果我们在web.xml中设置了多个servlet的时候,可以使用load-on-startup来指定servlet的加载顺序,服务器会根据load-on-startup的大小依次对servlet进行初始化。不过即使我们将load-on-startup设置重复也不会出现异常,服务器会自己决定初始化顺序。

    二、ServletConfig对象

       在Servlet配置文件中,可以使用一个或者多个<init-param>标签为Servlet配置一些初始化参数。当Web容器创建Servlet对象时,会自动将这些初始化参数封装到ServletConfig对象中,并在调用Servlet中init()方法时,将ServletConfig对象传递给Servlet。进而我们就能通过ServletConfig对象得到当前Servlet的初始化参数信息。

    1.在Web.xml配置参数

    	<servlet>
    		<servlet-name>LoginServlet</servlet-name>
    		<servlet-class>com.kiwi.servlet.LoginServlet</servlet-class>
    		<init-param>
    			<param-name>data</param-name>
    			<param-value>1234</param-value>
    		</init-param>
    		<init-param>
    			<param-name>data2</param-name>
    			<param-value>abcd</param-value>
    		</init-param>
    	</servlet>

    2.在Servlet中init()方法中获取

    	@Override
    	public void init(ServletConfig config) throws ServletException{
    		super.init(config);
    		
    		//1.得到指定参数的值
    		String data = this.getServletConfig().getInitParameter("data");
    		System.out.println("data = " + data);
    		System.out.println("********************");
    		
    		//2.得到所有的参数
    		Enumeration<String> datas = this.getServletConfig().getInitParameterNames();
    		while(datas.hasMoreElements()){
    			String name = datas.nextElement();
    			String value = this.getServletConfig().getInitParameter(name);
    			System.out.println(name + " = " + value);
    		}
    	}

    3.结果

    data = 1234
    ********************
    data = 1234
    data2 = abcd

    三、ServletContext对象

    1.ServletContext简介

       当Servlet容器在启动一个web应用时,会为它创建唯一的ServletContext对象。当Servlet容器终止一个web应用,则就会销毁它的ServletContext对象

       ServletContext,是一个全局的存储信息的空间,服务器开始,其就存在,服务器关闭,其才释放。request一个用户可以多个。session一个用户一个,而servletContext,所有用户公用一个。所以为了节省空间,提高效率ServletContext中要放必须的、重要的、所有用户需要共享的线程又是安全的一些信息。

       换种方式说,运行在Java虚拟机中每一个web应用程序都有一个与之相关的Servlet上下文。ServletContext对象时Web服务器中的一个已知根路径,Servlet上下文被定位于http://localhost:8080/项目名。/项目名 称为上下文路径,一个ServletContext对象表示了一个Web应用程序的上下文。

    Servlet上下文:Servlet上下文提供对应用程序中所有Servlet所共有的各种资源和功能的访问,Servlet上下文API用于设置应用程序中所有Servlet共有的信息,Servlet可能需要共享他们之间的共有信息,运行于同一服务器的Servlet有时也会共享资源,如jsp页面、文件和其他Servlet.

    举例说明:

       如,做一个购物类网站,要从数据库中提取物品信息,如果用session保存这些物品信息,每个用户都访问一遍数据库,效率就太低了;所以要用servlet上下文来保存,在服务器开始时,就访问数据库,将物品信息存入servlet上下文中,这样,每个用户只用从上下文中读入物品信息就行了。

       另外在jsp文件中,application是ServletContext的实例,由jsp容器默认创建,在servlet中调用getServletContext()得到ServletContext的实例。每个应用都会有一个ServletContext对象与之关联,当容器分布在多个虚拟机上时,web应用在所分布的每个虚拟机上都拥有一个ServletContext实例。

    2.ServletContext用途

    (1)访问web应用的初始化参数和属性

       getInitParameter()getInitParameterNames()

        应用开发人员利用初始化参数传递配置信息,典型的例子是web管理员的e-mail地址或一个持有关键数据的系统名称。

    在Web.xml文件中配置初始化参数

    	<context-param>
    		<param-name>email</param-name>
    		<param-value>123@sina.com</param-value>
    	</context-param>

    在Servlet中访问初始化参数

    		String email = this.getServletConfig().getInitParameter("email");
    		System.out.println("email = " + email);

    (2)上下文属性

    servlet可以通过名称将对象属性绑定到上下文,任何绑定到上下文属性都可以被同一个web应用的其它servlet使用。

    setAttribute()getAttribute()getAttributeNames()romoveAttribute()

    当信息需要在运行于分布式环境中的servlet之间共享时,信息被放入会话中,存储于数据库中。

    (3)读取资源文件

    例如读取Properties文件。

    private void readResource(){
    		//读取资源文件Properties
    		try{
    			InputStream inputStream = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");
    			Properties props = new Properties();
    			props.load(inputStream);
    			
    			String url = props.getProperty("url");
    			String username = props.getProperty("username");
    			String password = props.getProperty("password");
    			System.out.println("url = " + url + "
    username = " + username + "
    password = " + password);
    		}catch(Exception e){
    			e.printStackTrace();
    		}
    	}
  • 相关阅读:
    Flink开发_Flink中的函数接口
    Netty简介
    java NIO简单了解
    Kafka发送消息流程
    Kafka高性能的原理
    Hbase表设计
    Hbase的读写过程
    Hbase各组件职责
    什么是java的深浅拷贝?
    Flink问题1
  • 原文地址:https://www.cnblogs.com/yangang2013/p/5374266.html
Copyright © 2011-2022 走看看