Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
218 views
in Technique[技术] by (71.8m points)

java - How can I make Tomcat pre-compile JSPs on startup?

We're using both Apache Tomcat 6.0 and Jetty 6 where I work. We mostly use Jetty for testing (it's great for running embedded in JUnit tests) and Tomcat for production.

By default, Tomcat compiles JSPs on-the-fly as users request them. But this results in degraded performance for the first hit. It also highlights bizarre bugs in Tomcat's JSP compiler.

The Tomcat documentation gives recommendations for pre-compiling JSPs at build time using Ant (and a Maven plugin is also available)... but the resulting WAR contains Tomcat-specific stuff e.g. PageContextImpl.proprietaryEvaluate, so we can't use it in Jetty.

Is there some flag or setting we can use somewhere to force Tomcat to precompile all JSPs as soon as the WAR is initialized? We're prepared to wait a little longer on startup for this.

In advance: I know there's a way to pre-compile exactly one JSP by explicitly identifying a /servlet/load-on-startup tag in web.xml for one JSP. But for dozens or even hundreds of JSPs that becomes unmanageable.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

http://www.devshed.com/c/a/BrainDump/Tomcat-Capacity-Planning/


    project name="pre-compile-jsps" default="compile-jsp-servlets">

  <!-- Private properties. -- >
  <property name="webapp.dir" value="${basedir}/webapp-dir"/>
  <property name="tomcat.home" value="/opt/tomcat"/>
  <property name="jspc.pkg.prefix" value="com.mycompany"/>
  <property name="jspc.dir.prefix" value="com/mycompany"/> 

  <!-- Compilation properties. -->
  <property name="debug" value="on"/> 
  <property name="debuglevel" value="lines,vars,source"/>
  <property name="deprecation" value="on"/>
  <property name="encoding" value="ISO-8859-1"/>
  <property name="optimize" value="off"/>
  <property name="build.compiler" value="modern"/>
  <property name="source.version" value="1.5"/> 

  <!-- Initialize Paths. -->
  <path id="jspc.classpath">
    <fileset dir="${tomcat.home}/bin">
      <include name="*.jar"/>
    </fileset>
    <fileset dir="${tomcat.home}/server/lib">
      <include name="*.jar"/>
    </fileset>
    <fileset dir="${tomcat.home}/common/i18n">
      <include name="*.jar"/>
    </fileset>
    <fileset dir="${tomcat.home}/common/lib">
      <include name="*.jar"/>
    </fileset>
    <fileset dir="${webapp.dir}/WEB-INF">
      <include name="lib/*.jar"/>
    </fileset>
    <pathelement location="${webapp.dir}/WEB-INF/classes"/>
    <pathelement location="${ant.home}/lib/ant.jar"/>
    <pathelement location="${java.home}/../lib/tools.jar"/>
  </path>
  <property name="jspc.classpath" refid="jspc.classpath"/> 

  <!--========================================================== -->
  <!-- Generates Java source and a web.xml file from JSP files.                     -->
  <!-- ==========================================================
-->
  <target name="generate-jsp-java-src"> 
    <mkdir dir="${webapp.dir}/WEB-INF/jspc-src/${jspc.dir.prefix}"/>
    <taskdef classname="org.apache.jasper.JspC" name="jasper2">
      <classpath>
        <path refid="jspc.classpath"/>
      </classpath>
    </taskdef>
    <touch file="${webapp.dir}/WEB-INF/jspc-web.xml"/>
    <jasper2 uriroot="${webapp.dir}"
             package="${jspc.pkg.prefix}" 
          webXmlFragment="${webapp.dir}/WEB-INF/jspc-web.xml" 
             outputDir="${webapp.dir}/WEB-INF/jspc-src/${jspc.dir.prefix}"
             verbose="1"/>
  </target> 

  <!-- ========================================================== -->
  <!-- Compiles (generates Java class files from) the JSP servlet -->
  <!-- source code that was generated by the JspC task.            -->
  <!-- ========================================================== -->
  <target name="compile-jsp-servlets" depends="generate-jsp-java-src">
    <mkdir dir="${webapp.dir}/WEB-INF/classes"/>
    <javac srcdir="${webapp.dir}/WEB-INF/jspc-src"
           destdir="${webapp.dir}/WEB-INF/classes"
           includes="**/*.java"
           debug="${debug}"
           debuglevel="${debuglevel}"
           deprecation="${deprecation}"
           encoding="${encoding}"
           optimize="${optimize}"
           source="${source.version}">
      <classpath>
        <path refid="jspc.classpath"/>
      </classpath>
    </javac>
  </target> 

  <!-- ========================================================= -->
  <!-- Cleans any pre-compiled JSP source, classes, jspc-web.xml -->
  <!-- ========================================================= -->
  <target name="clean">
    <delete dir="${webapp.dir}/WEB-INF/jspc-src"/>
    <delete dir="${webapp.dir}/WEB-INF/classes/${jspc.dir.prefix}"/>
    <delete file="${webapp.dir}/WEB-INF/jspc-web.xml"/>
  </target>

</project

This build file will find all of your webapp’s JSP files, compile them into servlet classes, and generate servlet mappings for those JSP servlet classes. The servlet map pings it generates must go into your webapp’s WEB-INF/web.xml file, but it would be difficult to write an Ant build file that knows how to insert the servlet mappings into your web.xml file in a repeatable way every time the build file runs. Instead, we used an XML entity include so that the generated servlet mappings go into a new file every time the build file runs and that servlet mappings file can be inserted into your web.xml file via the XML entity include mechanism. To use it, your webapp’s WEB- INF/web.xml must have a special entity declaration at the top of the file, plus a reference to the entity in the content of the web.xml file where you want the servlet mappings file to be included. Here is how an empty servlet 2.5 webapp’s web.xml file looks with these modifications:

<!DOCTYPE jspc-webxml [
    <!ENTITY jspc-webxml SYSTEM "jspc-web.xml">
  ]> 

  <web-app xmlns=http://java.sun.com/xml/ns/javaee
      xmlns:xsi=http://www.w3.org/2001/ XMLSchema-instance 
      xsi:schemaLocation="http:// java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/ 
  javaee/web-app_2_5.xsd"
      version="2.5"> 

    <!-- We include the JspC-generated mappings here. -->
    &jspc-webxml; 

    <!-- Non-generated web.xml content goes here. --> 

  </web-app> 

Make sure your webapp’s web.xml file has the inline DTD (the DOCTYPE tag) all the way at the top of the file and the servlet 2.5 web-app schema declaration below that. Then, wherever you want to insert the generated servlet mappings in your web.xml file, put the entity reference &jspc-webxml; . Remember, the entity reference begins with an ampersand ( & ), then has the name of the entity, and ends with a semicolon ( ; ).

To use the build file, just edit it and set all of the properties at the top to values that match your setup, and then run it like this:

$ ant -f pre-compile-jsps.xml


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...