zoukankan      html  css  js  c++  java
  • 【JSP】JSP的介绍和基本原理

    JSP简介

    JSP的核心实质是Servlet技术。JSP是后来添加的基于Servlet的一种扩展技术。但二者在使用上有不同的方向。
    由于Servlet实质是一个Java类,因此非常适合用来处理业务逻辑。而如果Servlet要展示网页内容,就必须通过输出流对象将view层的代码通过字符串的形式输出,非常麻烦,且不易阅读和维护。另一方面,在JSP中可以直接编写视图层的代码如HTML,因此JSP的它主要用来展示网页内容。但是由于JSP实质是Servlet,因此JSP也是一种动态网页技术。
     
     
    而我们实际开发时,JSP只会用来展示网页视图内容,用Servlet来处理业务逻辑。因为 JSTL标签库 以及第三方框架提供的标签足够强大,我们甚至可以自定义标签 ,因此根本没有理由在JSP中写Java代码。
     
    JSP的视图代码可以是任何文本内容,如 HTML / XHTML ,XML , JSON , 甚至是txt。通常我们叫这些直接写在JSP中的文本叫做 模板文本数据。
     

    JSP, Servlet 和 JSP引擎

    我们常说,Tomcat是一个Servlet容器,而不说它是JSP容器,因为JSP实质是被转换为Servlet后再工作的。
    那我们为什么不直接使用Servlet呢?因为在Servlet中写视图层代码(HTML)非常狗血。但是Tomcat又只“认识”Servlet,因此就需要JSP引擎做一个转换工作。
     
    举个的例子,一切程序都是计算机可执行的机器代码,而直接编写机器代码是非常困难的,于是我们可以用C语言,用C写代码更加直观和易于阅读理解,C编译器会将C代码转换成对应的机器代码。这个例子中,Servlet就好比是机器代码,JSP好比是C语言,而JSP引擎 就好比是C编译器。
     
    因此:如果客户端请求的是一个JSP,则该JSP文件传递给JSP引擎,JSP引擎将JSP文件转译为Servlet的java文件,其实质就是这个Servlet来处理客户端的请求。
     

     JSP转换为Servlet的细节

     JSP按如下规则转换为Servlet:
    1、所有的 非  JSP 文本 ( 如HTML代码,XML代码),都将在生成的_jspService方法中以字符串的形式使用out对象输出。
    2、所有的<% %> 和 <%= %>脚本,将在他所在的地方原原本本对应插入到_jspService方法中去。所有的<%!  %>都将成为Servlet的类级别的成员。
           因此<%!  %>写在JSP页面代码的任何地方都没有任何区别。 <%-- --%>  JSP注释 将只保留在JSP代码中,不会存在转换后的servlet代码中
    3、EL,JSTL等被JSP引擎使用特殊转换。
     
     
    public void _jspService()
    {
            //.....
    
        try {
          response.setContentType("text/html; charset=UTF-8");
          pageContext = _jspxFactory.getPageContext(
                this, 
                request, 
                response,
                null,       /*page指令配置的error page 的URL*/
                true,      /*page质量配置的是否使用session*/
                8192,    /*page指令配置的out对象的缓存大小(kb)*/ 
                true);   /*page指令配置的out对象是否autoFlush*/
         
         //.....
    }

    JSP转译后的Servlet的继承结构

    JSP转译后的java文件在tomcat home下的work目录下找到。

    public interface Servlet {
         public void init(ServletConfig config) throws ServletException;
         public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
         public void destroy();
         public String getServletInfo();
         public ServletConfig getServletConfig();
    }
    
    public interface JspPage extends Servlet {
        public void jspInit();
        public void jspDestroy();
    }
    
    public interface HttpJspPage extends JspPage {
        public void _jspService(HttpServletRequest request,  HttpServletResponse response)
                                                              throws ServletException, IOException;
    }
    public abstract class HttpJspBase extends HttpServlet implements HttpJspPage {
        private static final long serialVersionUID = 1L;
        protected HttpJspBase() {
        }
    
        @Override
        public final void init(ServletConfig config)
            throws ServletException
        {
            super.init(config);
            jspInit();
            _jspInit();
        }
    
        @Override
        public String getServletInfo() {
            return Localizer.getMessage("jsp.engine.info");
        }
    
        @Override
        public final void destroy() {
            jspDestroy();
            _jspDestroy();
        }
    
        /**
         * Entry point into service.
         */
        @Override
        public final void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
        {
            _jspService(request, response);
        }
        @Override
        public void jspInit() {
        }
        public void _jspInit() {
        }
        @Override
        public void jspDestroy() {
        }
        protected void _jspDestroy() {
        }
    
        @Override
        public abstract void _jspService(HttpServletRequest request,
                                         HttpServletResponse response)
            throws ServletException, IOException;
    }
    可以看出,转译后的Servlet要实现上面的3个接口中的共 8 个 接口方法。然而,由于HttpJspBase 继承了HttpServlet,因此,7个方法已经全部间接实现了(只有_jspService方法没实现 )。
    由于JSP的特殊性,HttpJspBase 还是 重写了来自HttpServlet中的3方法,这3个方法正是一个Servlet的标准生命周期方法。而这3个方法内部又委托了 jspInit() 、  jspDestroy()  、 _jspService() 方法去实现。
    因此:
    1、可以认为,一个JSP的生命周期方法分别是通过 jspInit() 、  jspDestroy()  、 _jspService() 来实现的。如果某个JSP要做初始化和清理工作,则可以重写jspInit() 和 jspDestroy()方法实现。
    2、JSP转译后的Servlet必须实现_jspService方法,作为处理响应的逻辑方法。这点我们不用关心,JSP转译后自动根据你写的JSP代码实现。
    3、 因为HttpJspBase重写了 HttpServlet中的service方法,覆盖了根据请求发生选择不同处理方法doXXX的派发逻辑,对一个JSP使用任何HTTP请求方法都会调用_jspService方法处理。
     
     
     

    JSP的生命周期

    要理解JSP的生命周期就必须理解Servlet的生命周期,因为JSP的生命周期相比于Servlet只多了最开始的一步:转译工作。且这个工作只做一次(在JSP文件不改变的情况下)。
    在JSP被请求时,容器会先检查这个JSP是否被修改过,如果修改过,则重新转译,然后编译,其后的过程和Servlet生命周期一致。 如果没有,则直接调用内存中驻留的实例的方法。
     
    1、如果JSP文件是新的,则转译为Servlet java文件,然后编译为class文件。加载类到内存,创建一个(仅仅一个)Servlet对象。并执行jspInit,表示这个servlet被启用。
         如果不是,则直接调用驻留在内存上的实例的_jspService 方法。
    2、通过_jspService方法处理请求。多个请求同时请求同一个JSP的servlet实例,则这些请求会使用独立的线程去调用_jspService 方法。
    3、当此Servlet实例不再被使用、或者服务器关机时,调用jspDestroy,GC
     
     
     
  • 相关阅读:
    SQL Server Code tips (持续更新)
    Oracle 函数 “判断数据表中不存在的数据,才允许通过”
    Oracle 函数 “把当前的用户(审核人,审核通过后)插入到数据表中”
    Oracle 函数 “自动生成订单号”
    Oracle中的instr()函数 详解及应用
    Oracle中的substr()函数 详解及应用
    Spring实战(三)Spring中装配Bean的三种方式---XML、JavaConfig、AutoWire
    Spring实战(二)Spring容器和bean的生命周期
    Spring实战(一)Spring简介---呕心沥血只为让Java开发更简单。
    git、git bash、git shell
  • 原文地址:https://www.cnblogs.com/lulipro/p/7475355.html
Copyright © 2011-2022 走看看