Pregunta ¿Cómo puedo hacer que Tomcat precompile las JSP en el inicio?


Estamos usando Apache Tomcat 6.0 y Jetty 6 donde trabajo. Utilizamos principalmente Jetty para pruebas (es genial para ejecutar incrustado en pruebas JUnit) y Tomcat para producción.

De forma predeterminada, Tomcat compila JSP sobre la marcha a medida que los usuarios lo solicitan. Pero esto resulta en un rendimiento degradado para el primer golpe. También destaca bichos extraños en el compilador JSP de Tomcat.

los Documentación de Tomcat da recomendaciones para precompilar JSP en tiempo de compilación usando Ant (y también está disponible un complemento Maven) ... pero el WAR resultante contiene elementos específicos de Tomcat, p. PageContextImpl.proprietaryEvaluate, por lo que no podemos usarlo en Jetty.

¿Hay algún indicador o configuración que podamos usar en algún lugar para obligar a Tomcat a precompilar todos los JSP tan pronto como se inicialice WAR? Estamos preparados para esperar un poco más al inicio para esto.

De antemano: sé que hay una forma de precompilar exactamente uno JSP identificando explícitamente una etiqueta / servlet / load-on-startup en web.xml para un JSP. Pero para docenas o incluso cientos de JSPs que se vuelven inmanejables.


14
2018-01-31 00:30


origen


Respuestas:


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

Este archivo de compilación encontrará todos los archivos JSP de su aplicación web, los compilará en clases de servlet y generará asignaciones de servlets para esas clases de servlets JSP. Los pings de mapa de servlet que genera deben ir al archivo WEB-INF / web.xml de su webapp, pero sería difícil escribir un archivo de compilación Ant que sepa cómo insertar las asignaciones de servlets en su archivo web.xml de forma repetible cada vez que se ejecuta el archivo de compilación. En su lugar, utilizamos una entidad XML para que las asignaciones de servlets generadas vayan a un nuevo archivo cada vez que se ejecute el archivo de compilación y ese archivo de asignaciones de servlets pueda insertarse en su archivo web.xml mediante el mecanismo de inclusión de entidad XML. Para usarlo, WEB- INF / web.xml de su webapp debe tener una declaración de entidad especial en la parte superior del archivo, además de una referencia a la entidad en el contenido del archivo web.xml donde desea que el archivo de asignaciones de servlets incluido. Aquí se muestra cómo se ve un archivo web.xml de un servidor de aplicaciones 2.5 de webapp vacío con estas modificaciones:

<!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> 

Asegúrese de que el archivo web.xml de su webapp tenga el DTD en línea (la etiqueta DOCTYPE) en la parte superior del archivo y la declaración del esquema de la aplicación web de servlet 2.5 debajo de eso. Luego, donde sea que quiera insertar las asignaciones de servlet generadas en su archivo web.xml, coloque la entidad reference & jspc-webxml; . Recuerde, la referencia de la entidad comienza con un símbolo de unión (&), luego tiene el nombre de la entidad y termina con un punto y coma (;).

Para utilizar el archivo de compilación, simplemente edítelo y configure todas las propiedades en la parte superior a valores que coincidan con su configuración, y luego ejecútelo de esta manera:

$ ant -f pre-compile-jsps.xml


4
2018-05-01 04:05



Si sigues con la solución mencionada por duffymo apuntando al blog de Vinny Carpenter, tengo un consejo. Hubo un área que causó que mi contenedor se cuelgue indefinidamente al contactar al servidor local (específicamente en el método privado connect ()). Usar el siguiente truco fue mi solución:

    private void connect(final String urlString) {

        HttpURLConnection conn;
        try {
            final URL url = new URL(urlString);
            conn = (HttpURLConnection)url.openConnection();
            conn.setConnectTimeout(5000);
            //time it out quickly - otherwise hangs forever
            //seems to be an issue hitting localhost
            //will still precompile the page
            conn.setReadTimeout(100);
            conn.setAllowUserInteraction(true);
            conn.getInputStream();
            conn.disconnect();
        }
        catch (SocketTimeoutException e) {
            log.debug(e);
        }
        catch (IOException ioe) {
            log.error(ioe);
        }
    }

Configurar un tiempo de espera e ignorar el SocketTimeoutException funcionó (aunque no es la mejor solución). Además, el uso de este procedimiento significa que deberá especificar los JSP en web.xml. Esto fue suficiente para mis necesidades.


1
2018-02-16 00:09