学习笔记 ----servlet入门(一)(新建servlet及servlet的生命周期)

一、Servlet概述
        1.sun公司提供的动态web资源开发技术。本质是上一段java小程序,要求这个小程序必须实现Servlet接口,以便服务器能够调用。
        2.开发Servlet的两个步骤
        *实验:Servlet的快速入门
            (1)步骤一:写一个java程序实现Servlet接口 (此处直接继承了默认实现类GenericServlet)

 

            (2)将编译好的带包的.class放到WEB-INF/classes下以外,还要配置web应用的 web.xml注册Servlet
                <servlet>
                     <servlet-name>FirstServlet</servlet-name>
                     <servlet-class>cn.itheima.FirstServlet</servlet-class>

                </servlet>


            <servlet-mapping>
                 <servlet-name>FirstServlet</servlet-name>
                 <url-pattern>/FirstServlet</url-pattern>
            </servlet-mapping>

     

  3.利用MyEclipse开发Servlet

        
二、Servlet的详述

    1.生命周期:一件事物什么时候生,什么时候死,在生存期间必然会做的事情,所有这些放在一起就是该事物的生命明周期。


    2.Servlet的生命周期:通常情况下,servlet第一次被访问的时候在内存中创建对象,在创建后立即调用init()方法进行初始化。对于每一次请求都掉用service(req,resp)方法处  理请求,此时会用Request对象封装请求信息,并用Response对象(最初是空的)代表响应消息,传入到service方法里供使用。当service方法处理完成后,返回服务器服务器根据Response中的信息组织称响应消息返回给浏览器。响应结束后servlet并不销毁,一直驻留在内存中等待下一次请求。直到服务器关闭或web应用被移除出虚拟主机,servlet对象销毁并在销毁前调用destroy()方法做一些善后的事情。

     也就是说:servlet的生命周期是贯穿整个web服务的,当服务器启动,第一次调用该servlet时起,直到该web服务器关闭,servlet一直存在于内存中,并且存在的是单例模式。


    3.Servlet接口的继承结构
    Servlet接口:定义了一个servlet应该具有的方法,所有的Servlet都应该直接或间接实现此接口
    |
    |----GenericServlet:对Servlet接口的默认实现,通用Servlet,这是一个抽象类,其中的大部分方法都做了默认实现,只有service方法是一个抽象方法需要继承者自己实现
                |
                |----HttpServlet:对HTTP协议进行了优化的Servlet,继承自GenericServlet类,并且实现了其中的service抽象方法,默认的实现中判断了请求的请求方式,并根据请求方式的不同分别调用不同的doXXX()方法。通常我们直接继承HttpServlet即可
                

    4.web.xml注册Servlet的注意事项
        4.1利用<servlet><servlet-mapping>标签注册一个Servlet
            <servlet>
                  <servlet-name>FirstServlet</servlet-name>
                  <servlet-class>cn.itheima.FirstServlet</servlet-class>  注意:此处要的是一个Servlet的完整类名,不是包含.java或.class扩展的文件路径

            </servlet>

           <servlet-mapping>
                <servlet-name>FirstServlet</servlet-name>
                <url-pattern>/FirstServlet</url-pattern><!-- 此处的映射路径,是指在项目路径下:例:localhost:8080/***项目名//FirstServlet即可访问到该servlet-->
            </servlet-mapping>

 

       4.2一个<servlet>可以对应多个<servlet-mapping>

 

       4.3可以用*匹配符配置<serlvet-mapping>,但是要注意,必须是*.do、或者/开头 、的以/*结束的路径。

        ~由于匹配符的引入有可能一个虚拟路径会对应多个servlet-mapping,此时哪个最像找哪个servlet,并且*.do级别最低。


       4.4可以为<servlet>配置<load-on-startup>子标签,指定servlet随着服务器的启动而加载,其中配置的数值指定启动的顺序

           <servlet>
                <servlet-name>invoker</servlet-name>
                <servlet-class>
                    org.apache.catalina.servlets.InvokerServlet
                </servlet-class>
                <load-on-startup>2</load-on-startup>
            </servlet>


        4.5缺省servlet:如果一个servlet的对外访问路径被设置为/,则该servlet就是一个缺省servlet,其他servlet不处理的请求都由它来处理

                ~在conf/web.xml中配置了缺省servlet,对静态资源的访问和错误页面的输出就是由这个缺省servlet来处理的。如果我们自己写一个缺省servlet把web.xml中的缺省servlet覆盖的话,会导致静态web资源无法访问。所以不推荐配置。

       (这里有待探讨,例自定义一个servlet实现所有缺省servlet应该实现的功能,同时增加该servlet的一些功能,作为缺省servlet来使用。)


        4.6servlet的线程安全问题

                4.6.1由于通常情况下,一个servlet在内存只有一个实例处理请求,当多个请求发送过来的时候就会有多个线程操作该servlet对象,此时可能导致线程安全问题。
                        (1)serlvet的成员变量可能存在线程安全问题
                            *实验:定义一个成员变量 int i = 0;在doXXX()方法中进行i++操作并输出i值到客户端,此时由于延迟可能导致线程安全问题
                        (2)serlvet操作资源文件时,多个线程操作同一文件引发线程安全问题
                            *实验:请求带着一个参数过来,servlet将请求参数写入到一个文件,再读取该文件,将读取到的值打印到客户端上,有可能有线程安全问题
                            
                4.6.2解决方法
                        (1)利用同步代码块解决问题。缺陷是,同一时间同步代码块只能处理一个    请求,效率很低下,所以同步代码块中尽量只包含核心的导致线程安全问题的代码。
                        (2)为该servlet实现SingleThreadModel接口,此为一个标记接口,被标记的servlet将会在内存中保存一个servlet池,如果一个线程来了而池中没有servlet对象处理,则创建一个新的。如果池中有空闲的servlet则直接使用。这并不能真的解决线程安全问题。此接口已经被废弃。

                        (3)两种解决方案都不够完美,所以尽量不要在servlet中出现成员变量。

                        也就是说,变量全部转为局部变量,独立于方法中,即可解决高并发时的线程安全问题,如果必须要使用全局变量则一定要慎重。

                        
                        
三、ServletConfig
    1.代表servlet配置的对象,可以在web.xml中<servlet>中配置
        <servlet>
        <servlet-name>Demo5Servlet</servlet-name>
        <servlet-class>cn.itheima.Demo5Servlet</servlet-class>
        <init-param>
            <param-name>data1</param-name>
            <param-value>value1</param-value>
        </init-param>
      </servlet>
      然后在servlet中利用this.getServletConfig()获取ServletConfig对象,该对象提供了getInitParameter()和getInitParameterNames()方法,可以遍历出配置中的配置项。
      不想在servlet中写死的内容可以配置到此处。
    
    
四、ServletContext
    1.代表当前web应用的对象。
    
    2.作为域对象使用, 在不同servlet之间传递数据,作用范围是整个web应用
        ~域:一个域就理解为一个框,这里面可以放置数据,一个域既然称作域,他就有一个可以被看见的范围,这个范围内都可以对这个域中的数据进行操作,那这样的对象就叫做域对象。


    3.在web.xml可以配置整个web应用的初始化参数,利用ServletContext去获得

    <context-param>
        <param-name>param1</param-name>
        <param-value>pvalue1</param-value>
    </context-param>
    this.getServletContext().getInitParameter("param1")
    this.getServletContext().getInitParameterNames()
    
    4.在不同servlet之间进行转发
        this.getServletContext().getRequestDispatcher("/servlet/Demo10Servlet").forward(request, response);
        方法执行结束,service就会返回到服务器,再由服务器去调用目标servlet,其中request会重新创建,并将之前的request的数据拷贝进去。
    
    
    5.读取资源文件

        

            5.1由于相对路径默认相对的是java虚拟机启动的目录,所以我们直接写相对路径将会是相对于tomcat/bin目录,所以是拿不到资源的。如果写成绝对路径,当项目发布到其他环境时,绝对路径就错了。


            5.2为了解决这个问题ServletContext提供了this.getServletContext().getRealPath("/1.properties"),给进一个资源的虚拟路径,将会返回该资源在当前环境下的真实路径。this.getServletContext().getResourceAsStream("/1.properties"),给一个资源的虚拟路径返回到该资源真实路径的流。


            5.3当在非servlet下获取资源文件时,就没有ServletContext对象用了,此时只能用类加载器

                classLoader.getResourceAsStream("../../1.properties"),此方法利用类加载器直接将资源加载到内存中,有更新延迟的问题,以及如果文件太大,占用内存过大。
                classLoader.getResource("../1.properties").getPath(),直接返回资源的真实路径,没有更新延迟的问题。




WEB开发基本概念:


         HTML-----w3c组织提供,浏览器页面语言
        HTTP----美国的一个标准化组织,浏览器和服务器之间通信的规范,协议
        servlet规范----sun公司提供,定了servlet相关的内容,api
        servlet容器---servlet运行的环境,tomcat--apache
        web容器---所有能运行web应用的容器。



Servlet集成结构

Servlet接口:定义一个Servlet应该具有的最基本的方法
    |
    |--GenericServlet:抽象类,实现了Servlet接口,提供了对Servlet接口的默认实现,其中大部分的方法都做了默认实现,只有service方法没有实现是一个抽象方法。
                |
                |--HttpServlet:抽象类,此类在GenericServlet类的基础上提供了针对HTTP协议的增强的方法,其中service方法中判断请求的方式再去调用对应的doXXX方法。自己不要去覆盖service方法,而将代码卸载doXXX方法中,如果是get方式提交数据写在doGet中,post方式提交的数据卸载doPost中
                
                
                
                
生命周期:
    Servlet:服务器创建,第一次访问时创建,创建出来调用init,每次请求调用service,在服务器停止或web应用移除容器时销毁,销毁前调用destory。
    ServletConfig:服务器创建,Servlet实例时,调用init方法时作为参数使用传入,在Servlet中保存了对它的引用。随着Servlet的销毁而销毁。
    ServletContext:服务器创建,服务器启动,web应用加载后立即创建。服务器关闭或者web应用被移除出web容器时销毁。
    

域:一个可以被看见的范围
域对象:如果一个对象具有了一个可以被看见的范围则这个对象就叫做一个域的对象。



web应用中获取资源:
    传统方式:
        如果写相对路径,则相对域jdk启动目录,在web环境下找到了tomcat的启动目录,tomcat/bin
        如果写绝对路径,则写死在了程序里,在本机中可以,发布到其他主机的tomcat下时,路径很可能就是错的。
        
    解决方法:
        1.利用ServletContext,给以相对于当前web应用的路径,即可返回真实的硬盘路径,原理:就是在给的路径前拼上了当前web应用的硬盘路径,即使发布到其他的服务器,到时拼的就是哪个服务器所在的路径,所以不会出错。
            ServletContext.getRealPath
            ServletContext.getResourceAsStream
        2.利用类加载器加载资源,此处给的路径应该是相对于.class文件所在的根目录,web开发中就是相对WEB-INF/classes目录。
        (1)InputStream in = loader.getResourceAsStream("../1.properties");类似加载类的方式读取资源文件,第一次获取资源时,将资源加载到内存中。以后再获取的时候直接使用内存中缓存的。占用内存,不适合大型配置文件。由于只加载一次,每次修改配置文件后需要重启才起作用。
        (2)
            String path = loader.getResource("../1.properties").getPath();
            InputStream in = new FileInputStream(path);


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值