zoukankan      html  css  js  c++  java
  • JAVA 由浅及深之 Servlet

    原文出处:

    http://hxraid.iteye.com/blog/463701

    http://www.cnblogs.com/200911/archive/2012/05/02/2479880.html(cookie , session)

    http://www.cnblogs.com/cuiliang/archive/2011/10/21/2220671.html

    http://blog.csdn.net/muyihuakai/article/details/5858792

    http://www.cnblogs.com/JesseV/archive/2009/11/17/1605015.html


    1 常用的服务器:

    1IIS

    2Apache linux用的最多的)是一种web服务器,使用C语言写的

    3TomcatApache 总项目的一个,也是一种web服务器,是用java语言写的。叫做jspservelet的容器。

     

    三个概念的理解:

    Servlet容器<Web容器<应用服务器?

    Servlet容器的主要任务就是管理Servlet的生命周期;

    Web容器也称之为web服务器,主要任务就是管理和部署web应用的;

    应用服务器的功能非常强大,不仅可以管理和部署web应用,也可以部署EJB应用,实现容器管理的事务等等。。。

    Web服务器就是跟基于HTTP的请求打交道,而EJB容器更多是跟数据库,事务管理等服务接口交互,所以应用服务器的功能是很多的。

    常见的web服务器就是Tomcat,但Tomcat同样也是Servlet服务器;

    常见的应用服务器有WebLogic,WebSphere,但都是收费的;

    没有Servlet容器,可以用Web容器直接访问静态Html页面,比如安装了apache等;如果需要显示Jsp/Servlet,就需要安装一个Servlet容器;但是光有servlet容器也是不够的,它需要被解析为html显示,所以仍需要一个web容器;所以,我们常把web容器和Servlet容器视为一体,因为他们两个容器都有对方的功能实现了,都没有独立的存在了,比如tomcat!

    2 动态的网页技术:

    CGICommon GateWay Interface

    API(NSAPI ,ISAPI)

    ASP(active server page)

    PHP(personal home page)

    JSP/servelet(java server page)

     

    3 servelet 简介:

    (1)servelet 是一个服务器小应用程序。

    (2)用来完成B/S架构下,客户端请求的响应处理

    (3)平台独立,性能优良,能以线程的方式运行。

    (4)Servelet一般在容器中运行。

    (5)常见的servlet容器:Tomcat

      一个servlet就是Java编程语言中的一个类,它被用来扩展服务器的性能,服务器上驻留着可以通过“请求-响应”编程模型来访问的应用程序。虽然servlet可以对任何类型的请求产生响应,但通常只用来扩展Web服务器的应用程序。

     

    4 Servlet的工作模式

    (1)客户端(很可能是web浏览器)通过Http提出请求

    (2)Web服务器接收请求并将其发给Servlet

    (3)Servlet程序将接收该http请求并执行某种处理。

    (4)Servlet会将处理后的结果向web服务器返回应答。

    (5)Web服务器将从Servlet收到的应答发回给客户端。

      运行时阶段当容器接受到访问特定的servlet请求时,针对这个请求,创建对应的ServletRequest对象和 ServletResponse对象,并调用servlet的service()方法,service()根据从ServletRequest对象中获得 客户的请求信息并将调用相应的doxxx方法等进行响应,再通过ServletResponse对象生成响应结果,然后发送给客户端,最后销毁创建的ServletRequest 和ServletResponse

    5 Servlet生命周期:

    1)  装载Servlet : 在WEB.XML种配置<load-on-startup></load-on-startup>,指定当Web应用启动时,装载Servlet的次序。    
                                     当值为正数或零时:Servlet容器先加载数值小的servlet,再依次加载其他数值大的servlet.    
                                     当值为负或未定义:Servlet容器将在Web客户首次访问这个servlet时加载它 

              然而,Server通常会提供一个管理的选项,用于在Server启动时强制装载和初始化特定的Servlet。

    2)  Server创建一个Servlet的实例
    3)  Server调用Servlet的init()方法
    4)  一个客户端的请求到达Server(要看配置文件中如何配置,也许是最先的步骤
    5)  Server创建一个请求对象
    6)  Server创建一个响应对象
    7)  Server激活Servlet的service()方法,传递请求和响应对象作为参数
     
    8)  service()方法获得关于请求对象的信息,处理请求,访问其他资源,获得需要的信息
    9)  service()方法使用响应对象的方法,将响应传回Server,最终到达客户端。service()方法可能激活其它方法以处理请求,如doGet()或doPost()或程序员自己开发的新的方法。

    10) 对于更多的客户端请求,Server创建新的请求和响应对象,仍然激活此Servlet的service()方法,将这两个对象作为参数传递给它。如此重复以上的循环,但无需再次调用init()方法。一般Servlet只初始化一次(只有一个对象),当Server不再需要Servlet时(一般当Server关闭时),Server调用Servlet的Destroy()方法。


    6 Servlet 中service方法详解:

      每一个自定义的Servlet都必须实现Servlet的接口,Servlet接口中定义了五个方法,其中比较重要的三个方法涉及到Servlet的生命周期,分别是上文提到的init(),service(),destroy()方法。GenericServlet是一个通用的,不特定于任何协议的Servlet,它实现了Servlet接口。而HttpServlet基于HTTP协议,继承于GenericServlet,因此HttpServlet也实现了Servlet接口。所以我们定义Servlet的时候只需要继承HttpServlet即可

      HttpServlet 中重写了GenericServlet的service(),同时也对其进行了重载!源码如下:

      

    /**
       * 通过参数的向下转型,然后调用重载的
         */
    //重写
        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);//调用重载的方法
        }
    
    //重载
        protected void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException
        {
            String method = req.getMethod();
            if(method.equals("GET"))
            {
                long lastModified = getLastModified(req);
                if(lastModified == -1L)
                {
                    doGet(req, resp);
                } else
                {
                    long ifModifiedSince = req.getDateHeader("If-Modified-Since");
                    if(ifModifiedSince < (lastModified / 1000L) * 1000L)
                    {
                        maybeSetLastModified(resp, lastModified);
                        doGet(req, resp);
                    } else
                    {
                        resp.setStatus(304);
                    }
                }
            } else
            if(method.equals("HEAD"))
            {
                long lastModified = getLastModified(req);
                maybeSetLastModified(resp, lastModified);
                doHead(req, resp);
            } else
            if(method.equals("POST"))
                doPost(req, resp);
            else
            if(method.equals("PUT"))
                doPut(req, resp);
            else
            if(method.equals("DELETE"))
                doDelete(req, resp);
            else
            if(method.equals("OPTIONS"))
                doOptions(req, resp);
            else
            if(method.equals("TRACE"))
            {
                doTrace(req, resp);
            } else{
                String errMsg = lStrings.getString("http.method_not_implemented");
                Object errArgs[] = new Object[1];
                errArgs[0] = method;
                errMsg = MessageFormat.format(errMsg, errArgs);
                resp.sendError(501, errMsg);
            }
            }

     

    7 Servlet / Filter / Listener 的介绍和使用

      从使用上看可以分为三种:简单Servlet、过滤Servlet(Filter) 和监听Servlet(Listener)

    加载顺序为:context-param -> listener -> filter -> servlet

    1) 过滤器:

      是以一种组件的形式绑定在web应用程序当中的,与其他的Web应用程序组件不同的是,过滤器是采用链的方式进行处理的。一旦加入过滤器,所有的请求先交给过滤器处理,然后再访问相应的web资源的访问限制。

     

      实现过滤器:如果定义一个过滤器,则直接让一个类实现javax.servlet.Filter接口即可。

      Public void init(FilterConfig filterConfig)Throws ServletException

      public void doFilter(ServletRequest request,Servlet response,FilterChain chain)

      实现具体的过滤操作,然后通过FilterChain让请求继续向下传递。chain.doFilter(request,response);

      

      过滤器的销毁 public void destroy()

    2) 过滤器的应用:

    实例一:编码过滤器EncodingFilter.java

     

    为所有页面设置统一的编码:如果按照之前的做法,在每一个JSP或者Servlet中都重复编写request.setCharacterEncoding("GBK")的语句肯定是不可取的,会造成大量的代码重复。

     

    <!-- 编码过滤 -->

    方法1

    在web.xml中配置:

    <filter>
    
    <filter-name>encoding</filter-name>
    
    <filter-class>com.myTest.setCharacterEncodingFilter</filter-class>
    
    </filter>
    
    <filter-mapping>
    
    <filter-name>encoding</filter-name>
    
    <url-pattern>/*</url-pattern>
    
    </filter-mapping>

    在servlet中写:

    public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {
    
    request.setCharacterEncoding("GB18030");
    
    response.setCharacterEncoding("GB18030");
    
    chain.doFilter(request, response);
    
    }

    方法2

    <!-- 编码过滤 -->

    <filter>
    
      <filter-name>encoding</filter-name>
    
    <filter-class>
    
    com.myTest.setCharacterEncodingFilter
    
    </filter-class>
    
    <init-param>
    
    <param-name>charset</param-name>
    
    <param-value>GB18030</param-value>
    
    </init-param>
    
    </filter>
    public void init(FilterConfig config) throws ServletException {
    
    // TODO Auto-generated method stub
    
    this.charSet=config.getInitParameter("charset");//取得初始化参数
    
    }

    实例二:登陆验证:最早的做法是通过session的方式完成,但是每个页面都这样的话,则肯定造成大量代码的重复,而通过过滤器的方法即可避免这种重复操作。

    注意:向下转型:将ServletRequest转为HttpServletRequest。

    总结:过滤器属于自动执行的一种servlet,过滤器依然需要在web.xml文件中进行配置。过滤器常用的功能是可以完成常用的编码过滤,及登录验证。

     

     

    2) 监听器

      第三种servlet程序称为监听servlet,主要功能负责Web的各种操作,当相关的事件触发后将产生事件并对此事和request三种操作进行监听。

    (-)监听器主要对三个事件的动作监听:

    1 对servletContext的监听

    2 对session的监听

    3 对request的监听

       

      示例一:当你需要在处理任何客户端请求之前创建一个数据库连接,并且希望在整个应用过程中该连接都是可用的,这个时候ServletContextListener接口就会十分有用了。

      http://chenchh.iteye.com/blog/669956

      示例二:监听器:在线人员统计

      http://blog.csdn.net/zhangkai08111/article/details/2787972

    Session的操作:

    当一个新用户打开一个动态页时,服务器会为新用户分配session,并触发HttpsessionLisener接口中的sessionCreate()事件,但是在用户销毁时时却有两种不同的方式触发sessionDestroy()事件。

    方式一:调用HttpSession接口中的invalidate()方法,让一个session失效。

    方式二:超过了配置session的超时时间,session超时时间可以直接在项目中的web.xml中配置。

    <session-config>

    <session-timeout>5</session-timeout>

    <session_config>

    默认的超时时间为30分钟。

    3) Servlet跳转:

    1.客户端跳转:在Servlet中要想进行客户端跳转,(地址栏会发生变化)直接使用HttpServletResponse接口的sendRedirect()方法即可。(但是要注意的是,此跳转只能传递session范围的属性,而无法传递request范围的属性,这是因为request属性范围只有在服务器端跳转中才可以使用)。

    2.服务器端跳转:在Servlet中没有像JSP中的<jsp:forward>指令,所以如果要想执行服务器端跳转,就必须依靠RequestDispatcher接口完成。

    提供两方法:forword()和include()可完成跳转实现。

    但是还不够:如果要想使用此接口还要使用ServletRequest接口进行方法的实例化。

    ServletRequest接口进行方法的实例化:Public RequestDispatcher getRequestDispatcher(String path){}

    服务器端跳转之后,页面路径不会发生改变,而且此时可以在跳转后的JSP文件中接收到session及request范围的属性。

     


     

    Servlet 单例多线程详解:

    当Servlet容器收到一个Servlet请求,调度线程从线程池中选出一个工作者线程,将请求传递给该工作者线程,然后由该线程来执行Servlet的service方法。当这个线程正在执行的时候,容器收到另外一个请求,调度线程同样从线程池中选出另一个工作者线程来服务新的请求,容器并不关心这个请求是否访问的是同一个Servlet.当容器同时收到对同一个Servlet的多个请求的时候,那么这个Servlet的service()方法将在多线程中并发执行。 

    Servlet容器默认采用单实例多线程的方式来处理请求,这样减少产生Servlet实例的开销,提升了对请求的响应时间,对于Tomcat可以在server.xml中通过<Connector>元素设置线程池中线程的数目。

    PS:

    Servlet并非只是单例的. 当container开始启动,或是客户端发出请求服务时,Container会按照容器的配置负责加载和实例化一个Servlet(也可以配置为多个,不过一般不这么干).不过一般来说一个servlet只会有一个实例。

    1) Struts2的Action是原型,非单实例的;会对每一个请求,产生一个Action的实例来处理。 
    2) Struts1的Action,Spring的Ioc容器管理的bean 默认是单实例的.


    Struts1 Action是单实例的,spring mvc的controller也是如此。因此开发时要求必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts1 Action能作的事,并且要在开发时特别小心。Action资源必须是线程安全的或同步的。

    Spring的Ioc容器管理的bean 默认是单实例的。

    Struts2 Action对象为每一个请求产生一个实例,因此没有线程安全问题。(实际上,servlet容器给每个请求产生许多可丢弃的对象,并且不会导致性能和垃圾回收问题)。

    当Spring管理Struts2的Action时,bean默认是单实例的,可以通过配置参数将其设置为原型。(scope="prototype )

    http://www.2cto.com/kf/201302/189179.html

    http://wenku.baidu.com/view/4bf3802cb4daa58da0114ad1.html

    http://blog.csdn.net/ji_ju/article/details/8603387

     

     

  • 相关阅读:
    操作系统笔记------处理机调度
    操作系统笔记------进程同步(3)
    体系结构笔记------动态调度中的Tomasulo算法
    体系结构笔记------动态分支预测
    体系结构笔记------MIPS流水线的简单实现
    远程使用内网服务器的tensorboard和jupyter notebook
    tensorflow多分类标签转换成onehot
    anaconda的虚拟环境下,安装和管理python包的方法
    雪伦面经
    tensorflow官方MNIST数据集导入错误解决办法
  • 原文地址:https://www.cnblogs.com/alexlo/p/2954297.html
Copyright © 2011-2022 走看看