zoukankan      html  css  js  c++  java
  • (三)Servlet 知识点总结(来自那些年的笔记)

    (史上最全知识汇总)转载请贴上原文链接!

    作者:淮左白衣
    
    写于 2018年4月15日20:14:55
    

    如果,碰巧你打开了本篇博客,相信我,你想要的servlet知识,这里应该都能找到!!

    目录


    Servlet开发

    动态web资源开发,技术有两种:ServletJSP

    • 什么是Servlet开发

      Servlet是Sun公司提供的一门用于开发动态web资源的技术;

    • 如何用Servlet开发一个动态web资源(即如何编写一个servlet类)

      Sun公司在其 Api 中提供了一个Servlet接口,用户若想开发一个动态的Web资源(即开发一个java程序向浏览器输出数据),只需要完成以下两个步骤:
      1、编写一个java类,实现Servlet接口

      2、把开发好的java类部署到服务器中


    IDEA如何配置tomcat和WEB项目

    http://blog.csdn.net/yhao2014/article/details/45740111


    什么是生命周期方法

    一个对象拥有其自身的一个生命周期;在其生命周期的过程中,不同时间段,会执行不同的方法;这些方法,被称为 生命周期方法

    Servlet接口中的方法,就是生命周期方法 ;

    servlet接口代码:

        import java.io.IOException;
    
        public interface Servlet {
            void init(ServletConfig var1) throws ServletException;
    
            ServletConfig getServletConfig();
    
            void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
    
            String getServletInfo();
    
            void destroy();
    }

    其中我们重点关注的 service() 方法,我们为WEB应用写的逻辑,全放在这里,这是servlet的几个几个生命周期方法中,需要我们关注的一个方法;


    向浏览器写数据

    我们代表的是Tomcat服务器:我们编写一个servlet类,在service方法中获取响应头的输出流,然后往流中写数据;

        /**
         *
         * @param servletRequest   获得浏览器请求
         * @param servletResponse  获得服务器响应
         * @throws ServletException
         * @throws IOException
         */
        @Override
        public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
    //        获取回应,以便向浏览器写数据
            OutputStream out = servletResponse.getOutputStream() ;
    //        写数据
            out.write("hello Servlet".getBytes());
    //        关闭流
            out.close();
        }

    在Web.xml文件中配置servlet类:

    <!—注册servlet-->
    
     <servlet>
            <servlet-name>getnum</servlet-name>
            <servlet-class>day06.输出数据</servlet-class>
        </servlet>
    
    <!—映射关系,下面为地址,即在浏览器中输入的URN-->
    
     <servlet-mapping>
            <servlet-name>getnum</servlet-name>
            <url-pattern>/getnum</url-pattern>
        </servlet-mapping>

    <servlet> 用于注册Servlet,其中含有两个子标签:<servlet-name><servlet-class>

    <servlet-name> :为Servlet注册一个友好的名字 ;
    <servlet-class> :指明为哪一个Servlet类起个友好的名字,名字要写全限定名

    <servlet-mapping> 用于映射一个已注册的Servlet的一个对外访问路径,其中包含两个子标签:<servlet-name><url-pattern>

    <servlet-name> :指明为哪一个Servlet类配置对外访问路径
    <url-pattern> :指定对外访问的路径 ;

    同一个Servlet可以被映射到多个URL上,即多个 <servlet-mapping><servlet-name> 的值,可以是同一个Servlet ;

    伪静态:将一个动态web资源,映射到一个静态web资源上,就在映射地址上,写上后缀,诸如 .html ,浏览器在访问的时候,看到URL中的资源后缀名是 .html 以为访问的是一个静态资源,其实是被我们伪静态的一个动态资源;

        <servlet-mapping>
            <servlet-name>myform</servlet-name>
            <!--映射的地址,加上了 .html  的后缀-->
            <url-pattern>/myform.html</url-pattern>
        </servlet-mapping>

    映射地址通配符的问题

    Servlet映射到 URL中也可以使用 * 通配符,但是只能有两种固定的格式:
    1、*.扩展名 只要满足这个后缀名,就会访问到这里 ;
    2、以正斜杠(/)开头并用 /* 结尾的 ; /aa/* 只要是aa/,无论后面写什么,都无所谓;都会访问到这里 ;


    Servlet映射冲突问题

    其中谁长得最像的,就匹配谁; 并且通配符在前面的,优先级最低


    Servlet 调用过程

    在浏览器输入地址以后,到获取数据的过程中,都经历了什么?
    
    1. 首先,客户机浏览器根据ip地址,找到要访问的服务器;连接上这台服务器;然后客户机的浏览器发送http请求头给服务器;
    2. 服务器收到请求头,以后分析协议请求头,得知客户机要访问的主机、web应用、哪一个资源 ;
    3. 服务器上的动态资源,都对应着一个servlet类如果该资源是 第一次 被外部访问,也就意味着servlet类是第一次被访问,那么,服务器会创建一个该Servlet类的一个对象 ,这个对象有生命周期方法,创建完毕以后,自动执行init()方法,进行初始化; (只有这里,才会对 第一次 很在意)
    4. 然后,服务器创建代表请求的ServletRequest对象;代表回应的ServletResponse对象,这时候的ServletResponse是 空的回应头 (这一步是每次访问都会执行)
    5. 接着调用servlet的service()方法,来响应客户机的请求 ;执行我们写的逻辑 ;
    6. Servlet对象将service()方法的处理结果返回;也就是将数据写到了ServletResponse对象中
    7. 服务器,发现ServletResponse对象中有数据了 ,就会从ServletResponse中取出数据,构建一个http响应头,回送给客户机;
    8. 客户机的浏览器收到回应,解析出数据 ;

    备注:服务器在启动的时候,会把所有的web应用加载一次;注意,启动服务器的时候,并不会创建servlet实例对象并且访问不同的动态资源会创建不同的servlet实例对象 ;一个动态资源只会创建一个servlet对象(第一次被访问的时候,创建) ;


    Servlet 的一些细节

    • 什么是 servlet

      Servlet是一个供其他java程序(Servlet引擎)调用的java类,它不能独立运行,它的运行完全由Servlet引擎来控制和调度 ;

    • servlet对象,会被创建几个?

      针对客户端的多次对 同一个servlet,发起请求,通常情况下,服务器只会创建一个Servlet实例对象,创建完成以后,这个对象就会驻留在服务器内存中 ;为后续的其他请求服务,直到web服务器关闭或者对应的web应用从服务器中移除,这个Servlet实例对象就会被销毁 ;

    • 每次向服务器发起请求,都经由哪几个方法处理

      在servlet的整个生命周期内,servlet的init()方法,只会被调用一次,就是在第一次访问的时候而对于servlet的每次访问请求,都会调用一次servlet的service()方法


    请求头和响应头对象的创建时间、次数

    对于 每次 客户机的访问,服务器的servlet引擎,都会新建一个新的请求头对象和响应头 对象;其中请求头对象保存客户机传来的请求头 ,响应头对象刚创建的时候,里面不保存有任何数据;

    servlet引擎 将它们作为参数传给 service 方法;在service方法中,根据处理逻辑,往响应头中写入数据 ;,当 service 方法 执行结束以后,服务器发现响应头不再为空,就会取出数据,构建出一个http响应头回送给客户机 ;

    对于上述所说的,每次请求,都会创建一个响应头、请求头对象;服务器受得了吗

    答案:响应头、请求头对象,在内存中驻留的时间的是非常短的;请求结束,就会被销毁了;因此,只要不是高并发的访问服务器就可以接受


    HttpServlet

    我们上面说过,要想开发一个servlet程序,只需要写一个实现servlet接口,就好了;

    我们在源代码里面可以看出,servlet 接口定义了一个servlet的 所有的生命周期方法 ,但是我们在实际开发中,只关注 service() 方法 ;而我们要是直接实现 servlet 接口的话,其他几个方法,也需要我们写一下,这是很麻烦的事,因此Sun公司的 api 文档中,还提供了一个 已经实现好的servlet子类 GenericServlet

    但是 GenericServlet 是一个普适的实现类,而我们开发中,经常要与HTTP 打交道,这时候,他们又在 GenericServlet 的基础上,实现了一个 HttpServlet 类 ;因此,我们在写servlet程序的时候,一般不让GenericServlet;而是使用HttpServlet;

    Httpservlet 是能够处理Http请求的Servlet,他在原有的Servlet接口上添加了一些与HTTP协议相关的处理方法,比Servlet接口功能更为强大;因此,我们在开发时,通常都继承这个类,而非直接去实现Servalet或者使用GenericServlet;

    Httpservlet 在实现接口的时候,重写了 service() 方法,该方法体内的代码,会自动判断用户的请求方式如果为 GET 请求,则调用Httpservlet 的 doGet 方法;如果为 POST 请求,则调用Httpservlet 的 doPost 方法;

    注意:doGET()doPOST() 方法,是Httpservlet 自己定义的,并不是 GenericServletServlet 接口里面的 ;

    Httpservlet 重写以后的 service() 方法

      protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String method = req.getMethod();
            long lastModified;
            // 如果发现浏览器的请求方式是 GET ,则调用 this.doGet(req, resp)方法
            if (method.equals("GET")) {
                lastModified = this.getLastModified(req);
                if (lastModified == -1L) {
                    this.doGet(req, resp);
                } else {
                    long ifModifiedSince;
                    try {
                        ifModifiedSince = req.getDateHeader("If-Modified-Since");
                    } catch (IllegalArgumentException var9) {
                        ifModifiedSince = -1L;
                    }
    
                    if (ifModifiedSince < lastModified / 1000L * 1000L) {
                        this.maybeSetLastModified(resp, lastModified);
                        this.doGet(req, resp);
                    } else {
                        resp.setStatus(304);
                    }
                }
                // 判断浏览器的请求方式是否是 HEAD 
            } else if (method.equals("HEAD")) {
                lastModified = this.getLastModified(req);
                this.maybeSetLastModified(resp, lastModified);
                this.doHead(req, resp);
                // 判断浏览器的请求方式是否是 POST
            } else if (method.equals("POST")) {
                this.doPost(req, resp);
            } else if (method.equals("PUT")) {
                this.doPut(req, resp);
            } else if (method.equals("DELETE")) {
                this.doDelete(req, resp);
            } else if (method.equals("OPTIONS")) {
                this.doOptions(req, resp);
            } else if (method.equals("TRACE")) {
                this.doTrace(req, resp);
            } else {
                String errMsg = lStrings.getString("http.method_not_implemented");
                Object[] errArgs = new Object[]{method};
                errMsg = MessageFormat.format(errMsg, errArgs);
                resp.sendError(501, errMsg);
            }
    
        }

    从上面的源代码中,可以看出,我们以后在继承 Httpservlet 类的时候, 我们不需要,也没理由去重写这个service方法; 我们只需要重写 doGET()doPOST() 方法 ;


    load-on-startup 标签

    如果在 <servlet> 元素中配置了一个 <load-on-startup> 元素,那么WEB应用程序在被加载的的时候,就会装载并创建Servlet对象,以及调用init()方法 ;标签中间写的值,必须是正整数,数字越小,优先级越高 ; 优先级体现在,当有多个

     <servlet>
            <servlet-name>buycar</servlet-name>
            <servlet-class>day07.BuyCar</servlet-class>
            <load-on-startup>1</load-on-startup>
        </servlet>

    用途:为web应用写一个InitServlet,这个servlet配置为启动时装载,为整个web应用创建必要的数据库和逻辑 ;


    配置缺省的servlet

    这与上一篇中讲 配置缺省的WEB应用,是两码事 ;缺省应用是相对于服务器来说,而缺省servlet是相对于web应用来说;
    
    • 方法

      如果某个servlet的映射路径仅仅是一个正斜杠 / ,那么这个Servlet就成为当前web应用程序的缺省Servlet ;

      凡是在web.xml文件中,找不到匹配的 <servlet-mapping> 元素的URL,它们的访问请求都将被交给缺省的servlet处理,也就是说,缺省的servlet用于处理其他servlet都不处理的访问请求 ;

    • 用途

      首先明白一个道理:我们任何一个浏览器向服务器发送请求,其实都是访问servlet来的;当我们发送的地址,在服务器中没有对应的servlet映射到这个地址上时,就会去找缺省的servlet ;

    • 服务器默认缺省的servlet

      服务器已经帮我们配置好了一个缺省的servlet,它引用的servlet是阿帕奇的一个什么类;并且这个servlet还配置了<load-on-startup>,数值为1.意味着随着服务器的启动而启动 ;

      我们在浏览器中访问静态web资源,在web.xml文件中,明显是找不到匹配的 <servlet-mapping> ,因为,里面配置都是servlet类;
      因此,我们访问静态资源的时候,其实都是访问缺省的servlet都是由这个缺省的servlet完成的,它引用的阿帕奇的一个什么类,会自动去静态web资源的位置,寻找资源;如果没有这个资源,就会返回404页面;
      假如,我们自己也配置了一个缺省的servlet,那么就会覆盖掉服务器的缺省servlet,这样,服务器的静态资源,就无法访问了


    Servlet线程安全问题

    多个客户端 并发的访问 同一个 servlet时,web服务器会为每一个客户端的请求创建一个线程,并在这个线程上调用servlet的service方法 ;因此,如果service方法内,访问同一个资源的话,就会可能引发线程安全问题 ;现在是多个线程、一个servlet对象

    在服务器中,也就是这里的 service()方法,我们是不能加锁的;加锁的话,一个资源同一时间只有一个人可以访问到,这还是网站吗;

    如果,某个servlet实现了 SingleThreadModel 接口,那么servlet引擎将以 单线程模式 来调用其service方法 ;

    SingleThreadModel 接口中没有定义任何方法,只要在servlet类定义中增加SingleThreadModel接口的声明即可 ;这种接口,java通常叫做 标记接口

    对于实现了SingleThreadModel 接口的servlet,servlet引擎仍然支持对该servlet的多线程并发访问其采用的方式是产生多个servlet实例对象,并发的每个线程分别调用一个独立的servlet对象 ;(也就是说,当前servlet对象在为其他人服务的时候,有新的请求来访时,服务器会新建一个servlet对象来继续提高服务)现在是多个线程、多个servlet对象

    实现 SingleThreadModel 接口,并不能 真正的解决 servlet的线程安全问题, 因为servlet引擎会创建多个servlet实例对象;
    而真正意义上的解决多线程安全问题是指 一个servlet实例多个线程同时调用 的问题 ;

    SingleThreadModel 实质上并未解决这个问题,并且这个方法现在已经过时了;(哈哈哈,学了半天,是个过时的方法,妙啊!,,,)


    ServletConfig对象

    在Servlet的配置文件中,可以使用一个或者多个标签为servlet配置一些 初始化参数

    当servlet配置了初始化参数后,web容器在创建servlet实例对象时,会自定将这些初始化参数 封装到servletConfig对象 中,并在调用servlet的init()方法时,将servletConfig对象传递给servlet。进而,程序员可以通过 ServletConfig 对象,得到当前servlet的初始化参数信息。

    用于封装,不适合在程序中写死的数据 ;


    获取ServletConfig对象

    因为servlet类的爷爷,也就是 Genericservlet 类中已经将 init() 方法的servletConfig参数封装进一个对象里面,保存到本地。并且提供了获取这个对象的方法getServletConfig( )方法;但是这里封装具体是个什么对象,我不知道,我翻看源码,也没找到,只知道servletConfig 是个接口,服务器在这里使用了多态为了描述方便,我还称这个对象是servletConfig对象吧;

    看源代码:

        public ServletConfig getServletConfig() {
            return this.config;
        }
        // 在初始化一个servlet 之前,服务器会将参数封装进 实现了 ServletConfig接口 的对象里面
        public void init(ServletConfig config) throws ServletException {
            this.config = config;
            this.init();
        }

    因此可以在servlet对象中,通过 getServletConfig() 方法直接获取servletConfig对象 ;

    获取servletConfig对象中参数,可以根据名字获取,也可以一下子获取到所有的配置参数,返回到一个枚举中;

    //  根据名字获得对应的参数
        String getInitParameter(String var1);
    //  一下子获得所有的参数
        Enumeration<String> getInitParameterNames();

    其中遍历枚举类型的方法:

        while(e.hasMoreElements()){
            e.nextElement() ;
        }

    服务器传递给servlet的对象

    客户机访问web资源的时候,首先客户机的浏览器会先访问到服务器,然后,服务器根据请求头,才知道要具体访问哪一个资源;在具体访问某一个资源的时候,又会创建Servlet对象,在创建servlet对象的时候,会传递许多对象给servlet;

    传递的对象有Request,Response,servletConfig,servletContext,session,cookie;


    ServletContext对象

    WEB容器在启动时,他会为 每个web应用程序 都创建一个对应的 ServletContext 对象,它代表当前的web应用 被当前WEB应用中的 所有servlet 共享 (注意是servlet,而不是整个web)

    ServletConfig 接口中维护了 ServletContext 对象的引用

    public interface ServletConfig {
        String getServletName();
        //  定义了一个方法,获得 SercletContext 对象
        ServletContext getServletContext();
    
        String getInitParameter(String var1);
    
        Enumeration<String> getInitParameterNames();
    }

    GenericServlet 类中的具体实现:

     public ServletConfig getServletConfig() {
            return this.config;
        }
        //  获取到servletContext对象 
        public ServletContext getServletContext() {
            return this.getServletConfig().getServletContext();
        }

    开发人员在编写servlet时,可以通过servletConfig.getServletContext() 方法获得ServletContext对象 ;它拥有一些全局性方法 ;当然我们还是愿意直接使用 getServletContext() 方法直接获得;

    向其中添加数据:使用servletContext 添加数据,就是添加一个属性,setAttribute(键值对) ;


    ServletContext对象生命周期

    创建:在服务器启动的时候,就会去加载每一个web应用,在加载web应用的时候,就会为每一个web应用创建一个ServletContext对象 ;

    销毁:停掉服务器;或者删除某一个web应用 ;就跟servlet对象一样,销毁的时机 ;


    ServletContext类中方法的应用

    ServletContext 也是一个接口,我翻看源码,也没找与它相关的实现类。。。为了描述方便,也称之为ServletContext对象 ;
    

    由于一个web应用中的所有servlet共享同一个ServletContext对象,所以单个servlet可以通过servletContext对象实现数据共享网络聊天室);
    因为servletContext对象的共享属性,servletContext对象通常也被称为 context域对象

    • 获取web应用的初始化参数 ;

      前面讲ServletConfig的时候,说可以通过 ServletConfig 对象获得初始化参数 ;
      我们这里讲的 servletContext 对象,也可以获得初始化参数 ;

      其实是这两个接口,都定义了相同的抽象方法;

        String getInitParameter(String var1);
    
        Enumeration<String> getInitParameterNames();

    转发

    说到转发,就要提到重定向了;
    

    重定向:就是浏览器向服务器提交一个请求,服务器告诉它没有这个资源,资源在某某某哪里,让浏览器自己去找某某某;这里客户机发 两次 请求 ;

    转发:则是服务器虽然没有这个资源,但是服务器帮浏览器去问有这个资源的人要 ;
    这里客户机发一次请求 ;

    转发技术应用的特别广;servlet不适合输出数据的;因为我们想输出的数据格式漂亮一点的话,就需要写HTML,css;在servlet里面写这些,简直要命;因此,servlet会做一个转发,将它产生的数据转发到jsp(后面会讲到什么是JSP)那里,jsp再对数据做美化,然后输出 ;


    如何在servlet中进行转发

    1. servlet 中将 http请求 转发给 jsp
    2. 并且将数据传递到jsp中;

      大家可能还记得,servletContext,我们说过它是一个WEB应用所共享的;但是这里并不能使用Context域。会有 线程安全问题
      假如在传递数据之前,有其他请求也往servletContext添加了数据,并且键的名字是一样的,那么传递过去的数据,就被改变了;所以这里应该使用request域,一个请求持有一个request ;

    3. 通过 servletContext 对象的 getRequestDispatcher(jsp的路径) ;该方法返回一个转发对象 RequestDispatcher
    4. 调用转发对象的 forward(请求头,应答头); 就会将请求转到jsp那里 ;
    5. 在jsp中,是可以嵌套java的
    6. 在 <% java代码 %> 在这里面写java代码;将数据提取出去,写到应答头中 ;可以在<% %>
      外部任意嵌套HTML标签,对数据进行修饰 ;

    在jsp中 application 代表 servletContext ;取数据,就是获取属性的方法:getAttribute(键) ;取出来的时候,是一个object,需要强转 ;


    利用ServletContext对象读取资源文件

    • (资源)配置文件的类型

      首先,明确javaweb中,配置文件一般有两种:xml文件和properties文件
      当配置文件的数据没有关系的时候,使用properties文件;假如,配置文件的数据之间有关系,就选用xml文件;

    • 读取资源文件的方法

      利用 servletContextgetResourceAsStream(路径) ;返回一个 inputStream

           getServletContext().getResourceAsStream() ;
    
    • getResourceAsStream(路径)的参数路径(相对路径)

      在Javaweb中 ,路径分隔符是 : /

      当我们的路径是给 浏览器 用的时候, 代表的是 网站
      当我们的路径是给 服务器 用的时候, 代表 web应用

      例如:
      •如果配置文件是放在src下面的,而我们 IDEA 中 src 下面的类文件是在 WEB-INF文件夹 下面的 classes文件夹 下面,因此对应的目录是 /WEB-INF/classes/db.properties
      •如果是放在 WebRoot 目录下,对应的目录是: /db.properties

      简单说,就是对应在服务器中的文件夹目录 ;


    Web中的FileInputStream

    在javaweb中读取一个文件,就不要再像小时候学java那样了,使用 fileInputSteam ;而是改用servletContext的getResourceAsStream 方法;

    在web中因为 fileInputSteam 的路径,除非你写明白绝对路径,否则就是相对路径,相对的是java虚拟机的路径,而java虚拟机在其他地方啊,所以导致写相对路径根本访问不到;除非在虚拟机的目录下添加文件 ;在java中,getResourceAsStream(路径) 相对路径是java类的所在文件路径


    读取资源文件的三种方式

    Web应用中的servlet程序读取资源文件

    1. 通过servletContext对象的getResourceAsStream(配置文件在服务器的路径) 方法获得 input 流
    2. 通过servletContext对象的 getRealPath(配置文件在服务器的路径) 返回配置文件的绝对路径;

      获得文件的 绝对路径 然后就可以使用 FileInputStream 读取了 ;这种方式,一般用在下载的时候,需要获取资源的名称 ;从绝对路径中截取 ;

    Web应用中的普通java文件读取资源文件

    如果读取资源文件的程序不是servlet的话,那就没有servletContext对象给我们用了

    就只能通过类加载器来读取了 ;但是资源文件不能太大 ;它会把资源文件当做类一样,加载到内存中,文件太大,内存就会溢出 ;


    为什么要通过 类加载器读 取读取资源文件?

    答案:因为servlet类有一个servletContext对象的,这个对象是整个web中的servlet对象共享的;它能操控整个web应用的资源;因此,就可以读取资源文件;

    而在普通的java类中,是无法直接获取到servletContext对象的;除非,传进来一个,这样耦合性就变高了 ;

    没有这个servletContext对象,我们要怎么才能在普通java的类中加载资源文件呢?用到类加载器;既然类加载器可以把java类加载到服务器中,那么资源文件是和java类文件在一个文件目录下面的,那么资源文件同样也可以被类加载器加载 ;


    如何获得类加载器

    类加载器只有一个,只要随便获得一个类的类加载器就可以了;

    获取类加载器的方法:类名.class.getClassLoader() ;

    类加载器加载资源的方法: getResourceAsStream(资源文件路径) ;返回一个InputStream ;


    关于类加载器读取资源的方法的参数问题

    getResourceAsStream(资源文件路径);这里的路径到底怎么写
    

    这里的资源文件路径,得看使用的 类加载器 怎么得到的

    下面的2个方法,都是直接 class.getResourceAsStream ;没有 getClassLoader 并且路径都是以 / 开头的 ;

    • 任意类名.class.getResourceAsStream (“/文件所在的位置”); (注意这里有个 / ,)

      文件所在的位置从包名开始写

    • 和资源文件文件在同一个目录下的 类名.class.getResourceAsStream (“/文件所在的位置”);

      文件所在的位置从包名开始写, 】注意其实这里是可以不写 / ;为了和下面的区分,我们还是写上;


    下面的3个方法,都是通过 getClassLoader ,并且路径都不是以 / 开头的 ;

    • 任意类名.class.getClassLoader().getResourceAsStream(“文件所在的位置”);

      文件所在的位置从包名开始写

    • 任意类名.class.getClassLoader().getResource(“文件所在的位置”).openStream();

      文件所在的位置从包名开始写

    • 任意类名.class.getClassLoader().getResource(“文件所在的位置”)..openConnection().getInputStream();

      文件所在的位置从包名开始写

      我们发现 其实资源路劲,都是从包名开始写,只是开头,是否有 / 的区别 ;

      有getClassLoader 就没有 / ;


    类加载器加载文件的一个问题

    场景: 类加载器加载类文件到内存中,只会加载一次;只要这个类曾经被加载到内存中,就会创建这个类的字节码对象;只要内存中还有这个字节码对象,就会不会再次加载这个类;

    问题:因此,当我们使用类加载器加载资源文件的时候,只要类加载器加载过资源文件一次,后面只要服务器不停,即使更新了资源文件,新的资源文件也不会被加载到内存中,因此,导致了一个资源更新,察觉不到的问题:

    解决方法:我们还是要使用传统的方法——读取文件流来读取文件,不能使用类加载器加载资源 ;因此,我们先使用类加载器获得资源的绝对路径

    方法类名.class.getClassLoader.getResource(资源的相对路径).getPath() ;通过这样获取资源的绝对路径;得到绝对路径以后,就可以使用传统java的读取方法读取文件了;
    再使用FileInputStream读取文件 ;

    说到这,我发现 类加载器 和 servletContext 有诸多相似的地方,不知道他们之间有着什么联系


    为整个web应用配置参数

    在web.xml中使用 <context-param> 标签 ;这个标签中的参数,在服务器加载这个web应用的时候,会自动把参数添加到 servletContext 对象中 ;(笔者没有笔误,这里确实是 servletContext 对象,而不是上文说的 servletConfig 对象

    用途:为整个web应用配置共享配置 ;

  • 相关阅读:
    17. Letter Combinations of a Phone Number
    16. 3Sum Closest
    15. 3Sum
    14. Longest Common Prefix
    13. Roman to Integer
    12. Integer to Roman
    11. Container With Most Water
    10. Regular Expression Matching
    9. Palindrome Number
    8. String to Integer (atoi)
  • 原文地址:https://www.cnblogs.com/young-youth/p/11665731.html
Copyright © 2011-2022 走看看