Tomcat使用Jasper引擎解析JSP- JspServlet源码分析

熟悉JAVA web开发的朋友都知道JSP会被转换成java文件(预编译),然后编译成class使用,即按照JSP-->java-->class的过程进行编译。

由于JVM只认识class文件,它不知道什么是JSP,因此在tomcat中 如何把JSP解析成java文件 就是本文所要描述的问题。

 

其他翻译内容参考:Tomcat官方文档翻译 

如有错误,请予指正。

什么是Jasper

  Jasper是tomcat中使用的JSP引擎,在Tomcat 6中使用的是Jasper 2,相对于原来的版本作了不少的改进,比如:JSP的标签缓冲池、后台编译、页面改变时自动重新编译、Eclipse中JDT编译等等。

  那么Jasper到底是做什么的呢?

  简单的说,就是把JVM不认识的JSP文件解析成java文件,然后编译成class文件提供使用。目前有很多的JSP解析引擎,Tomcat中使用的是Jasper。

  在Tomcat中可以通过配置 CATALINA_HOME/conf/web.xml 中的内容,配置Jasper的选项(web.xml中的内容很长,截取其中的一部分):

复制代码
  <!-- The JSP page compiler and execution servlet, which is the mechanism  -->
  <!-- used by Tomcat to support JSP pages.  Traditionally, this servlet    -->
  <!-- is mapped to the URL pattern "*.jsp".  This servlet supports the     -->
  <!-- following initialization parameters (default values are in square    -->
  <!-- brackets):                                                           -->
  <!--                                                                      -->
  <!--   checkInterval       If development is false and checkInterval is   -->
  <!--                       greater than zero, background compilations are -->
  <!--                       enabled. checkInterval is the time in seconds  -->
  <!--                       between checks to see if a JSP page (and its   -->
  <!--                       dependent files) needs to  be recompiled. [0]  -->
  <!--                                                                      -->
  <!--   classdebuginfo      Should the class file be compiled with         -->
  <!--                       debugging information?  [true]                 -->
  <!--                                                                      -->
  <!--   classpath           What class path should I use while compiling   -->
  <!--                       generated servlets?  [Created dynamically      -->
  <!--                       based on the current web application]          -->
  <!--                                                                      -->
  <!--   compiler            Which compiler Ant should use to compile JSP   -->
  <!--                       pages.  See the jasper documentation for more  -->
  <!--                       information.                                   -->
  <!--                                                                      -->
  <!--   compilerSourceVM    Compiler source VM. [1.5]                      -->
  <!--                                                                      -->
  <!--   compilerTargetVM    Compiler target VM. [1.5]                      -->  
  <!--                                                                      -->
  <!--   development         Is Jasper used in development mode? If true,   -->
  <!--                       the frequency at which JSPs are checked for    -->
  <!--                       modification may be specified via the          -->
  <!--                       modificationTestInterval parameter. [true]     -->
  <!--                                                                      -->
  <!--   displaySourceFragment                                              -->
  <!--                       Should a source fragment be included in        -->
  <!--                       exception messages? [true]                     -->
  <!--                                                                      -->
  <!--   dumpSmap            Should the SMAP info for JSR45 debugging be    -->
  <!--                       dumped to a file? [false]                      -->
  <!--                       False if suppressSmap is true                  -->
  <!--                                                                      -->
  <!--   enablePooling       Determines whether tag handler pooling is      -->
  <!--                       enabled. This is a compilation option. It will -->
  <!--                       not alter the behaviour of JSPs that have      -->
  <!--                       already been compiled. [true]                  -->
  <!--                                                                      -->
  <!--   engineOptionsClass  Allows specifying the Options class used to    -->
  <!--                       configure Jasper. If not present, the default  -->
  <!--                       EmbeddedServletOptions will be used.           -->
  <!--                                                                      -->
  <!--   errorOnUseBeanInvalidClassAttribute                                -->
  <!--                       Should Jasper issue an error when the value of -->
  <!--                       the class attribute in an useBean action is    -->
  <!--                       not a valid bean class?  [true]                -->
  <!--                                                                      -->
  <!--   fork                Tell Ant to fork compiles of JSP pages so that -->
  <!--                       a separate JVM is used for JSP page compiles   -->
  <!--                       from the one Tomcat is running in. [true]      -->
  <!--                                                                      -->
  <!--   genStringAsCharArray                                               -->
  <!--                       Should text strings be generated as char       -->
  <!--                       arrays, to improve performance in some cases?  -->
  <!--                       [false]                                        -->
  <!--                                                                      -->
  <!--   ieClassId           The class-id value to be sent to Internet      -->
  <!--                       Explorer when using <jsp:plugin> tags.         -->
  <!--                       [clsid:8AD9C840-044E-11D1-B3E9-00805F499D93]   -->
  <!--                                                                      -->
  <!--   javaEncoding        Java file encoding to use for generating java  -->
  <!--                       source files. [UTF8]                           -->
  <!--                                                                      -->
  <!--   keepgenerated       Should we keep the generated Java source code  -->
  <!--                       for each page instead of deleting it? [true]   -->
  <!--                                                                      -->
  <!--   mappedfile          Should we generate static content with one     -->
  <!--                       print statement per input line, to ease        -->
  <!--                       debugging?  [true]                             -->
  <!--                                                                      -->
  <!--   modificationTestInterval                                           -->
  <!--                       Causes a JSP (and its dependent files) to not  -->
  <!--                       be checked for modification during the         -->
  <!--                       specified time interval (in seconds) from the  -->
  <!--                       last time the JSP was checked for              -->
  <!--                       modification. A value of 0 will cause the JSP  -->
  <!--                       to be checked on every access.                 -->
  <!--                       Used in development mode only. [4]             -->
  <!--                                                                      -->
  <!--   recompileOnFail     If a JSP compilation fails should the          -->
  <!--                       modificationTestInterval be ignored and the    -->
  <!--                       next access trigger a re-compilation attempt?  -->
  <!--                       Used in development mode only and is disabled  -->
  <!--                       by default as compilation may be expensive and -->
  <!--                       could lead to excessive resource usage.        -->
  <!--                       [false]                                        -->
  <!--                                                                      -->
  <!--   scratchdir          What scratch directory should we use when      -->
  <!--                       compiling JSP pages?  [default work directory  -->
  <!--                       for the current web application]               -->
  <!--                                                                      -->
  <!--   suppressSmap        Should the generation of SMAP info for JSR45   -->
  <!--                       debugging be suppressed?  [false]              -->
  <!--                                                                      -->
  <!--   trimSpaces          Should white spaces in template text between   -->
  <!--                       actions or directives be trimmed?  [false]     -->
  <!--                                                                      -->
  <!--   xpoweredBy          Determines whether X-Powered-By response       -->
  <!--                       header is added by generated servlet  [false]  -->
  <!--                                                                      -->
  <!-- If you wish to use Jikes to compile JSP pages:                       -->
  <!--   Please see the "Using Jikes" section of the Jasper-HowTo           -->
  <!--   page in the Tomcat documentation.                                  -->

    <servlet>
        <servlet-name>jsp</servlet-name>
        <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
        <init-param>
            <param-name>fork</param-name>
            <param-value>false</param-value>
        </init-param>
        <init-param>
            <param-name>xpoweredBy</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>3</load-on-startup>
    </servlet>
复制代码

  具体的参数,上面都有解释,这里就不多赘述了。

  都是些调节JSP编译的参数,比如多长时间检测一次,debug的调试信息相关配置,编译信息等等。

如何利用Japser.Jspc自定义预编译JSP

  1 jasper相关jar包

  在tomcat6中提供了几个jasper的jar包,相对于之前版本,去掉了jasper-compiler.jar以及jasper-runtime.jar,合并为jasper.jar

  另外如果开发者自己想要编译JSP,还需要使用ant以及tomcat-juli.jar。

  2 ant相关jar包

  其中ant相关的jar包可以去官网下载ant.zip,然后解压提取其中lib内的jar包。

  3 tomcat-juli相关jar包

  tomcat-juli.jar位于CATALINA_HOME/bin/目录下。

 

  在Eclipse的构建路径下添加上述相关的jar包即可,然后创建测试类:

  添加JAR包步骤:右键工程-->Properties-->Java Build Path-->Libraries-->Add External JARs-->选择添加的JAR包-->OK

复制代码
package com.test;
import org.apache.jasper.JspC;

public class testCompiler{
    public String jspcTest(){  
        String error="";  
        try {  
            JspC jspc = new JspC();  
            //第一种方式
            String[] arg0 = {"-uriroot", "F:/apache-tomcat-6.0.43/webapps/ROOT", "-d", "F:/test", 
                    "index.jsp" }; 
            jspc.setArgs(arg0); 
            
            //第二种方式
            /*jspc.setUriroot("F:/apache-tomcat-6.0.43/webapps/ROOT");//web应用的root目录  
            jspc.setOutputDir("F:/test");//.java文件和.class文件的输出目录  
            jspc.setJspFiles("index.jsp");//要编译的jsp  */
            
            jspc.setCompile(true);//是否编译 false或不指定的话只生成.java文件  
            jspc.execute(); 
        }catch(Exception e){
            error=e.toString();
        }
        return error;  
    }
    public static void main(String args[]){  
        testCompiler t=new testCompiler();  
        System.out.println(t.jspcTest());  
    }  
}  
复制代码

  可以使用两种方式进行自定义的JSP编译。

  测试后,可以在 F:/test 目录下发现编译出的index.jsp的java文件以及class文件。

参考

【1】Jasper2 JSP引擎:http://tomcat.apache.org/tomcat-6.0-doc/jasper-howto.html

【2】解读JSP解析过程:http://www.cnblogs.com/zollty/p/3309310.html

【3】使用Jspc编译JSP文件:http://kjah.iteye.com/blog/625588


前言:Jsper模块: 负责jsp页面的解析、jsp属性的验证,同时也负责将jsp页面动态转换为java代码并编译成class文件。


1.简介

Tomcat 8.5使用Jasper 2 JSP引擎来实现JavaServer Pages 2.3规范。
Jasper 2被重新设计,显著改善了Jasper的表现。 除了一般的代码改进之外,以下的更改还包括:

  • JSP Custom Tag Pooling - 为JSP自定义标记实例化的java对象现在可以被池化和重用。这极大地提高了使用自定义标记的JSP页面的性能。
  • Background JSP compilation - 如果您对已经编译过的JSP页面进行了更改,那么Jasper 2可以在后台重新编译该页面。以前编译的JSP页面仍然可用来服务请求。一旦新页面被成功编译,它将取代旧页面。这有助于提高生产服务器上JSP页面的可用性。
  • Recompile JSP when included page changes - Jasper 2现在可以检测到,从JSP中包含的一个页面已经改变了,然后重新编译了父JSP。
  • JDT used to compile JSP pages - 现在,Eclipse JDT Java编译器被用于执行JSP Java源代码编译。这个编译器从容器类加载器加载源依赖项。Ant和javac仍然可以使用。

Jasper是org.apache.jasper.servlet.JspServlet使用servlet实现类 下面的coding是对JSPServlet源码的分析。

[java]  view plain  copy
  1. /** 
  2.  * Copyright © 2017 http://blog.csdn.net/noseparte © Like the wind, like rain 
  3.  * @Author Noseparte 
  4.  * @Compile 2017年12月7日 -- 下午4:34:36 
  5.  * @Version 1.0 
  6.  * @Description  JspServlet源码分析 
  7.  */  
  8. public class JspServlet extends HttpServlet implements PeriodicEventListener {  
  9.       
  10.     /** 
  11.      * @see transient修饰词释义 
  12.      * java语言的关键字,变量修饰符,如果用transient声明一个实例变量, 
  13.      * 当对象存储时,它的值不需要维持。换句话来说就是,用transient关键字标记的成员变量不参与序列化过程。 
  14.      */  
  15.     private static final long serialVersionUID = 1L;  
  16.     private final transient Log log = LogFactory.getLog(JspServlet.class);    
  17.     private transient ServletContext context;   //ServletContext对象包含在ServletConfig对象中,当servlet被初始化时,Web服务器提供servlet。  
  18.     private ServletConfig config;  //servlet容器使用的servlet配置对象在初始化期间将信息传递给servlet。  
  19.     private transient Options options; //一个类来保存所有与JSP引擎相关的init参数。  
  20.     private transient JspRuntimeContext rctxt; //用于跟踪JSP编译时文件依赖项的类  
  21.     private String jspFile;  
  22.   
  23.     /** 
  24.      * javax.servlet.GenericServlet由servlet容器调用,以指示servlet正在被放置到服务中。 
  25.      * 看到Servlet.init(javax.servlet.ServletConfig)。 
  26.      * 该实现存储从servlet容器接收的ServletConfig对象,以供以后使用。 
  27.      * 当覆盖该方法的这种形式时,调用super.init(config)。 
  28.      * @param config 
  29.      */  
  30.     public void init(ServletConfig config) throws ServletException {  
  31.         super.init(config);  
  32.         this.config = config;  
  33.         this.context = config.getServletContext();  
  34.   
  35.         String engineOptionsName = config.getInitParameter("engineOptionsClass");  
  36.   
  37.         if ((Constants.IS_SECURITY_ENABLED) && (engineOptionsName != null)) {  
  38.             this.log.info(Localizer.getMessage("jsp.info.ignoreSetting",  
  39.                     "engineOptionsClass", engineOptionsName));  
  40.             engineOptionsName = null;  
  41.         }  
  42.   
  43.         if (engineOptionsName != null) {  
  44.             try {  
  45.                 ClassLoader loader = Thread.currentThread()  
  46.                                            .getContextClassLoader();  
  47.                 Class<?> engineOptionsClass = loader.loadClass(engineOptionsName);  
  48.                 Class<?>[] ctorSig = { ServletConfig.class, ServletContext.class };  
  49.                 Constructor<?> ctor = engineOptionsClass.getConstructor(ctorSig);  
  50.                 Object[] args = { config, this.context };  
  51.                 this.options = ((Options) ctor.newInstance(args));  
  52.             } catch (Throwable e) {  
  53.                 e = ExceptionUtils.unwrapInvocationTargetException(e);  
  54.                 ExceptionUtils.handleThrowable(e);  
  55.   
  56.                 this.log.warn("Failed to load engineOptionsClass", e);  
  57.   
  58.                 this.options = new EmbeddedServletOptions(config, this.context);  
  59.             }  
  60.         } else {  
  61.             this.options = new EmbeddedServletOptions(config, this.context);  
  62.         }  
  63.   
  64.         this.rctxt = new JspRuntimeContext(this.context, this.options);  
  65.   
  66.         if (config.getInitParameter("jspFile") != null) {  
  67.             this.jspFile = config.getInitParameter("jspFile");  
  68.   
  69.             try {  
  70.                 if (null == this.context.getResource(this.jspFile)) {  
  71.                     return;  
  72.                 }  
  73.             } catch (MalformedURLException e) {  
  74.                 throw new ServletException("cannot locate jsp file", e);  
  75.             }  
  76.   
  77.             try {  
  78.                 if (SecurityUtil.isPackageProtectionEnabled()) {  
  79.                     AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {  
  80.                             public Object run()  
  81.                                 throws IOException, ServletException {  
  82.                                 JspServlet.this.serviceJspFile(nullnull,  
  83.                                     JspServlet.this.jspFile, true);  
  84.   
  85.                                 return null;  
  86.                             }  
  87.                         });  
  88.                 } else {  
  89.                     serviceJspFile(nullnullthis.jspFile, true);  
  90.                 }  
  91.             } catch (IOException e) {  
  92.                 throw new ServletException("Could not precompile jsp: " +  
  93.                     this.jspFile, e);  
  94.             } catch (PrivilegedActionException e) {  
  95.                 Throwable t = e.getCause();  
  96.   
  97.                 if ((t instanceof ServletException)) {  
  98.                     throw ((ServletException) t);  
  99.                 }  
  100.   
  101.                 throw new ServletException("Could not precompile jsp: " +  
  102.                     this.jspFile, e);  
  103.             }  
  104.         }  
  105.   
  106.         if (this.log.isDebugEnabled()) {  
  107.             this.log.debug(Localizer.getMessage("jsp.message.scratch.dir.is",  
  108.                     this.options.getScratchDir().toString()));  
  109.   
  110.             this.log.debug(Localizer.getMessage(  
  111.                     "jsp.message.dont.modify.servlets"));  
  112.         }  
  113.     }  
  114.   
  115.     /** 
  116.      * 返回JspServletWrappers存在的jsp数量 
  117.      * @return 
  118.      */  
  119.     public int getJspCount() {  
  120.         return this.rctxt.getJspCount();  
  121.     }  
  122.   
  123.     /** 
  124.      * 重新设置JSP重新加载计数器。 
  125.      * @param count 
  126.      */  
  127.     public void setJspReloadCount(int count) {  
  128.         this.rctxt.setJspReloadCount(count);  
  129.     }  
  130.   
  131.     /** 
  132.      * 获取已重新加载的jsp的数量。 
  133.      * @return 
  134.      */  
  135.     public int getJspReloadCount() {  
  136.         return this.rctxt.getJspReloadCount();  
  137.     }  
  138.   
  139.     /** 
  140.      * 获得JSP限制队列中JSP的数量 
  141.      * @return 
  142.      */  
  143.     public int getJspQueueLength() {  
  144.         return this.rctxt.getJspQueueLength();  
  145.     }  
  146.   
  147.     /** 
  148.      * 获得已卸载的jsp的数量。 
  149.      * @return 
  150.      */  
  151.     public int getJspUnloadCount() {  
  152.         return this.rctxt.getJspUnloadCount();  
  153.     }  
  154.   
  155.     boolean preCompile(HttpServletRequest request) throws ServletException {  
  156.         String queryString = request.getQueryString();  
  157.   
  158.         if (queryString == null) {  
  159.             return false;  
  160.         }  
  161.   
  162.         int start = queryString.indexOf(Constants.PRECOMPILE);  
  163.   
  164.         if (start < 0) {  
  165.             return false;  
  166.         }  
  167.   
  168.         queryString = queryString.substring(start +  
  169.                 Constants.PRECOMPILE.length());  
  170.   
  171.         if (queryString.length() == 0) {  
  172.             return true;  
  173.         }  
  174.   
  175.         if (queryString.startsWith("&")) {  
  176.             return true;  
  177.         }  
  178.   
  179.         if (!queryString.startsWith("=")) {  
  180.             return false;  
  181.         }  
  182.   
  183.         int limit = queryString.length();  
  184.         int ampersand = queryString.indexOf('&');  
  185.   
  186.         if (ampersand > 0) {  
  187.             limit = ampersand;  
  188.         }  
  189.   
  190.         String value = queryString.substring(1, limit);  
  191.   
  192.         if (value.equals("true")) {  
  193.             return true;  
  194.         }  
  195.   
  196.         if (value.equals("false")) {  
  197.             return true;  
  198.         }  
  199.   
  200.         throw new ServletException("Cannot have request parameter " +  
  201.             Constants.PRECOMPILE + " set to " + value);  
  202.     }  
  203.   
  204.     /** 
  205.      * javax.servlet.http.HttpServlet从公共服务方法接收标准HTTP请求,并将它们分派到这个类中定义的doMethod方法。 
  206.      * 该方法是servlet.service(javax.servlet的一个特定于http的版本。 
  207.      * ServletRequest,javax.servlet.ServletResponse)方法。没有必要覆盖这个方法。 
  208.      */  
  209.     public void service(HttpServletRequest request, HttpServletResponse response)  
  210.         throws ServletException, IOException {  
  211.         String jspUri = this.jspFile;  
  212.   
  213.         if (jspUri == null) {  
  214.             jspUri = (String) request.getAttribute(  
  215.                     "javax.servlet.include.servlet_path");  
  216.   
  217.             if (jspUri != null) {  
  218.                 String pathInfo = (String) request.getAttribute(  
  219.                         "javax.servlet.include.path_info");  
  220.   
  221.                 if (pathInfo != null) {  
  222.                     jspUri = jspUri + pathInfo;  
  223.                 }  
  224.             } else {  
  225.                 jspUri = request.getServletPath();  
  226.   
  227.                 String pathInfo = request.getPathInfo();  
  228.   
  229.                 if (pathInfo != null) {  
  230.                     jspUri = jspUri + pathInfo;  
  231.                 }  
  232.             }  
  233.         }  
  234.   
  235.         if (this.log.isDebugEnabled()) {  
  236.             this.log.debug("JspEngine --> " + jspUri);  
  237.             this.log.debug("\t     ServletPath: " + request.getServletPath());  
  238.             this.log.debug("\t        PathInfo: " + request.getPathInfo());  
  239.             this.log.debug("\t        RealPath: " +  
  240.                 this.context.getRealPath(jspUri));  
  241.             this.log.debug("\t      RequestURI: " + request.getRequestURI());  
  242.             this.log.debug("\t     QueryString: " + request.getQueryString());  
  243.         }  
  244.   
  245.         try {  
  246.             boolean precompile = preCompile(request);  
  247.             serviceJspFile(request, response, jspUri, precompile);  
  248.         } catch (RuntimeException e) {  
  249.             throw e;  
  250.         } catch (ServletException e) {  
  251.             throw e;  
  252.         } catch (IOException e) {  
  253.             throw e;  
  254.         } catch (Throwable e) {  
  255.             ExceptionUtils.handleThrowable(e);  
  256.             throw new ServletException(e);  
  257.         }  
  258.     }  
  259.   
  260.     /** 
  261.      * javax.servlet.GenericServlet由servlet容器调用, 
  262.      * 以指示servlet正在被从服务中取出/销毁 
  263.      */  
  264.     public void destroy() {  
  265.         if (this.log.isDebugEnabled()) {  
  266.             this.log.debug("JspServlet.destroy()");  
  267.         }  
  268.   
  269.         this.rctxt.destroy();  
  270.     }  
  271.   
  272.     /** 
  273.      * 周期性的eventlistener,执行一个周期性任务,比如重新加载,等等。 
  274.      */  
  275.     public void periodicEvent() {  
  276.         this.rctxt.checkUnload();  
  277.         this.rctxt.checkCompile();  
  278.     }  
  279.   
  280.     private void serviceJspFile(HttpServletRequest request,  
  281.         HttpServletResponse response, String jspUri, boolean precompile)  
  282.         throws ServletException, IOException {  
  283.         JspServletWrapper wrapper = this.rctxt.getWrapper(jspUri);  
  284.   
  285.         if (wrapper == null) {  
  286.             synchronized (this) {  
  287.                 wrapper = this.rctxt.getWrapper(jspUri);  
  288.   
  289.                 if (wrapper == null) {  
  290.                     if (null == this.context.getResource(jspUri)) {  
  291.                         handleMissingResource(request, response, jspUri);  
  292.   
  293.                         return;  
  294.                     }  
  295.   
  296.                     wrapper = new JspServletWrapper(this.config, this.options,  
  297.                             jspUri, this.rctxt);  
  298.   
  299.                     this.rctxt.addWrapper(jspUri, wrapper);  
  300.                 }  
  301.             }  
  302.         }  
  303.   
  304.         try {  
  305.             wrapper.service(request, response, precompile);  
  306.         } catch (FileNotFoundException fnfe) {  
  307.             handleMissingResource(request, response, jspUri);  
  308.         }  
  309.     }  
  310.   
  311.     private void handleMissingResource(HttpServletRequest request,  
  312.         HttpServletResponse response, String jspUri)  
  313.         throws ServletException, IOException {  
  314.         String includeRequestUri = (String) request.getAttribute(  
  315.                 "javax.servlet.include.request_uri");  
  316.   
  317.         if (includeRequestUri != null) {  
  318.             String msg = Localizer.getMessage("jsp.error.file.not.found", jspUri);  
  319.   
  320.             throw new ServletException(SecurityUtil.filter(msg));  
  321.         }  
  322.   
  323.         try {  
  324.             response.sendError(404, request.getRequestURI());  
  325.         } catch (IllegalStateException ise) {  
  326.             this.log.error(Localizer.getMessage("jsp.error.file.not.found",  
  327.                     jspUri));  
  328.         }  
  329.     }  
  330. }  




2.配置

在默认情况下,Jasper在做web应用程序开发时被配置为使用。
实现Jasper的servlet是在全局中使用init参数配置的  $CATALINA_BASE/conf/web.xml .
  • checkInterval 如果开发是false,而checkInterval大于零,则启用后台编译。checkInterval是在检查之间的几秒之间的时间,以查看是否需要重新编译JSP页面(及其依赖的文件)。默认值0秒。
  • classdebuginfo 应该使用调试信息编译类文件吗?真或假,默认为真。
  • classpath 定义用于编译生成的servlet的类路径。该参数如果产生影响只有org.apache.jasper.Constants.SERVLET_CLASSPATH不设置当Jasper在Tomcat中使用时,这个属性总是被设置的。默认情况下,类路径是根据当前的web应用程序动态创建的。
  • compiler 应该使用哪个编译器来编译JSP页面。此值的有效值与Ant的javac任务的编译器属性相同。如果没有设置值,那么将使用默认的Eclipse JDT Java编译器,而不是使用Ant。没有默认值。如果该属性设置为setenv。应该使用sh bat来添加ant.jar,ant-launcher jar。jar和工具。jar到CLASSPATH环境变量。
  • compilerSourceVM -什么JDK版本是与之兼容的? (Default value: 1.7)
  • compilerTargetVM - 生成的文件与什么JDK版本兼容? (Default value: 1.7)
  • development - Jasper在发展模式中使用了吗?如果是正确的,可以通过变更测试间隔参数指定对jsp进行修改的频率。真或假,默认为真。
  • displaySourceFragment 是否应该将一个源片段包含在异常消息中?真或假,默认为真。
  • dumpSmap 是否应该将JSR45调试的SMAP信息转储到文件中?真或假,默认为假。如果抑制映射为真,则是假的。
  • enablePooling 确定是否启用了标记处理程序池。这是一个编译选项。它不会改变已经编译的jsp的行为。真或假,默认为真。
  • engineOptionsClass - 允许指定用于配置Jasper的选项类。如果不存在,将使用默认的嵌入服务。如果在SecurityManager下运行该选项会被忽略.
  • errorOnUseBeanInvalidClassAttribute 当一个使用bean操作中的类属性值不是一个有效的bean类时,贾斯珀是否会发出错误?真或假,默认为真。
  • fork 是否有Ant fork JSP页面编译,以便在与Tomcat不同的JVM中执行它们?真或假,默认为真。
  • genStringAsCharArray 是否应该将文本字符串作为char数组生成,以提高某些情况下的性能?默认的错误。
  • ieClassId 当使用了标签时,类id值将被发送给Internet Explorer。默认clsid:8 ad9c840 - 044 e - 11 - d1 b3e9 f499d93——00805。
  • javaEncoding 用于生成Java源文件的Java文件编码。use UTF8违约。
  • keepgenerated 我们应该为每个页面保留生成的Java源代码,而不是删除它吗?真或假,默认为真。
  • mappedfile 我们是否应该在每个输入行中生成静态内容,以简化调试工作?真或假,默认为真。
  • maxLoadedJsps 将为web应用程序加载的jsp的最大数量。如果加载的jsp数量超过了这一数量,那么最近使用的jsp将会被卸载,以便在任何时候加载的jsp的数量不会超过这个限制。0或更少的值表示没有限制。默认为-1
  • jspIdleTimeout 在它被卸载之前,JSP可以在秒内空闲的时间。0或更少的值表示永远不会卸载。默认为 -1
  • modificationTestInterval 在指定的时间间隔(以秒为单位)从上一次检查JSP进行修改时,导致JSP(及其相关文件)在指定的时间间隔内不被检查。值为0将导致在每次访问时对JSP进行检查。仅用于开发模式。默认为4秒。
  • recompileOnFail 如果一个JSP编译失败了,是否应该忽略修改后的测试间隔,而下一个访问将触发重新编译的尝试?只在开发模式中使用,默认情况下是禁用的,因为编译可能很昂贵,可能导致资源的过度使用。
  • scratchdir - 在编译JSP页面时,我们应该使用什么scratch目录?默认是当前web应用程序的工作目录。如果在SecurityManager下运行,这个选项会被忽略。
  • suppressSmap 对于jsr 45调试的SMAP信息是否应该被抑制?真或假,默认为假。
  • trimSpaces - 应该删除完全由空格组成的模板文本吗?真或假,默认为假。
  • xpoweredBy 定由生成的servlet添加的x-power-响应头是否被添加。真或假,默认为假。
  • strictQuoteEscaping 当scriptlet表达式用于属性值时,是否应该严格地应用JSP.1.6中的规则来转义引号中的字符?真或假,默认为真。
  • quoteAttributeEL 当在JSP页面的属性值中使用EL时,是否应该将JSP.1.6中所描述的属性引用的规则应用到表达式中?真或假,默认为真。
Eclipse JDT中的Java编译器被包括为默认编译器。 它是一个高级的Java编译器,它将加载来自Tomcat类加载器的所有依赖项,这将极大地帮助在大型安装中使用数十个jar进行编译。 在快速服务器上,这将允许甚至大型JSP页面的次秒重新编译周期。
在以前的Tomcat版本中使用的Apache Ant可以通过配置上面解释的编译器属性来代替新的编译器。

3.知识点

正如在bug 39089中所描述的,一个已知的JVM问题,bug 6294277,可能会导致 java.lang.InternalError: name is too long to represent,当编译一个很大的jsp文件时  如果观察到这一点,那么就可以用下面的一个方法来解决这个问题:

  • 减小JSP的大小
  • 通过将抑制映射设置为true,禁用SMAP生成和JSR-045支持。


4.产品配置

可以完成的主要JSP优化是对JSP的预编译。 然而,这可能是不可能的(例如,在使用jsp-property group特性时)或实际操作,在这种情况下,贾斯珀servlet的配置变得至关重要。
当在一个生产Tomcat服务器中使用Jasper 2时,您应该考虑从默认配置中做出以下更改:
  • development 要禁用JSP页面编译的访问检查,将此设置为false。
  • genStringAsCharArray 为了生成更高效的char数组,请将其设置为true。
  • modificationTestInterval 如果开发必须以任何理由(如jsp的动态生成)被设置为true,那么将其设置为高值将会极大地提高性能。
  • trimSpaces 为了从响应中删除无用的字节,将其设置为true。



5.Web应用程序

使用Ant是使用JSPC编译web应用程序的首选方法。注意,在预编译jsp时,SMAP信息只有在最后的类中包含,如果抑制映射是假的,编译是正确的。使用下面给出的脚本(一个类似的脚本包含在"deployer"下载中)来预编译一个webapp:

<project name="Webapp Precompilation" default="all" basedir=".">

   <import file="${tomcat.home}/bin/catalina-tasks.xml"/>

   <target name="jspc">

    <jasper
             validateXml="false"
             uriroot="${webapp.path}"
             webXmlFragment="${webapp.path}/WEB-INF/generated_web.xml"
             outputDir="${webapp.path}/WEB-INF/src" />

  </target>

  <target name="compile">

    <mkdir dir="${webapp.path}/WEB-INF/classes"/>
    <mkdir dir="${webapp.path}/WEB-INF/lib"/>

    <javac destdir="${webapp.path}/WEB-INF/classes"
           optimize="off"
           debug="on" failοnerrοr="false"
           srcdir="${webapp.path}/WEB-INF/src"
           excludes="**/*.smap">
      <classpath>
        <pathelement location="${webapp.path}/WEB-INF/classes"/>
        <fileset dir="${webapp.path}/WEB-INF/lib">
          <include name="*.jar"/>
        </fileset>
        <pathelement location="${tomcat.home}/lib"/>
        <fileset dir="${tomcat.home}/lib">
          <include name="*.jar"/>
        </fileset>
        <fileset dir="${tomcat.home}/bin">
          <include name="*.jar"/>
        </fileset>
      </classpath>
      <include name="**" />
      <exclude name="tags/**" />
    </javac>

  </target>

  <target name="all" depends="jspc,compile">
  </target>

  <target name="cleanup">
    <delete>
        <fileset dir="${webapp.path}/WEB-INF/src"/>
        <fileset dir="${webapp.path}/WEB-INF/classes/org/apache/jsp"/>
    </delete>
  </target>

</project>
可以使用下面的命令行来运行脚本(用Tomcat基路径替换标记,以及应该预先编译的webapp的路径):
$ANT_HOME/bin/ant -Dtomcat.home=<$TOMCAT_HOME> -Dwebapp.path=<$WEBAPP_PATH>
然后,在预编译期间生成的servlet的声明和映射必须添加到web应用程序部署描述符中。添加   ${webapp.path}/WEB-INF/generated_web.xml     ${webapp.path}/WEB-INF/web.xml   文件中.重新启动web应用程序(使用管理器)并对其进行测试,以验证它是否与预编译的servlet运行良好。 在web应用程序部署描述符中放置适当的标记也可以用于自动插入生成的servlet声明和使用Ant过滤功能的映射。 这实际上是如何将所有与Tomcat一起分发的web应用程序作为构建过程的一部分自动编译的。
在jasper任务中,您可以使用选项 addWebXmlMappings 映射来自动合并 ${webapp.path}/WEB-INF/generated_web.xml 当前的web应用程序部署描述符在$webapp.path/ WEB-INF /web.xml中。 当您想要在jsp中使用Java 6特性时,添加以下javac编译器任务属性:source="1.6"目标="1.6"。 对于实时应用程序,您还可以使用  optimize="on" 进行编译,而不需要调试信息 debug="off"
当您不想在第一个jsp语法错误中停止jsp生成时,使用 failOnError="false" ,并使用 showSuccess="true" 将所有成功的jsp都打印出来。 有时候,当您在$webapp中清理生成的java源文件时,这是非常有用的。 路径}  ${webapp.path}/WEB-INF/src 和编译jsp servlet类 ${webapp.path}/WEB-INF/classes/org/apache/jsp.
提示:
  • 当您切换到另一个Tomcat版本时,使用新的Tomcat版本重新生成并重新编译您的jsp。
  • 使用java系统属性在服务器运行时禁用PageContext池org.apache.jasper.runtime.JspFactoryImpl.USE_POOL = false和限制缓冲org.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER = true请注意,更改默认值可能会影响性能,但它将根据应用程序的不同而有所不同。


6.优化

在Jasper提供的一些扩展点中,用户可以优化他们的环境的行为。

这些扩展点的第一个是标记插件机制。 这允许为web应用程序提供可替代的标记处理程序实现。 标签插件是通过tagPlugins.xml 文件位于WEB-INF中。 JSTL的一个示例插件包含在Jasper中。 第二个扩展点是表达式语言解释器。 可以通过ServletContext配置可选的解释器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值