Как я могу сделать Tomcat прекомпилировать JSP при запуске? - PullRequest
14 голосов
/ 31 января 2009

Мы используем Apache Tomcat 6.0 и Jetty 6, где я работаю. В основном мы используем Jetty для тестирования (он отлично подходит для запуска встроенных в тесты JUnit) и Tomcat для производства.

По умолчанию Tomcat компилирует JSP на лету, когда пользователи их запрашивают. Но это приводит к снижению производительности для первого удара. Это также подчеркивает странных ошибок в JSP-компиляторе Tomcat.

В документации Tomcat содержатся рекомендации по предварительной компиляции JSP во время сборки с использованием Ant (и также доступен плагин Maven) ... но в результате WAR содержит специфичные для Tomcat вещи, например PageContextImpl.pprietaryEvaluate, поэтому мы не можем использовать его в Jetty.

Есть ли какой-нибудь флаг или параметр, который мы можем использовать где-нибудь, чтобы заставить Tomcat прекомпилировать все JSP, как только инициализируется WAR? Мы готовы немного подождать при запуске для этого.

Заранее: я знаю, что есть способ предварительно скомпилировать точно один JSP, явно указав тег / servlet / load-on-startup в web.xml для одного JSP. Но для десятков или даже сотен JSP, которые становятся неуправляемыми.

Ответы [ 2 ]

4 голосов
/ 01 мая 2009

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

Этот файл сборки найдет все файлы JSP вашего веб-приложения, скомпилирует их в классы сервлетов и сгенерирует сопоставления сервлетов для этих классов сервлетов JSP. Пинги, генерируемые картой сервлетов, которые она генерирует, должны попадать в файл WEB-INF / web.xml вашего веб-приложения, но было бы трудно написать файл сборки Ant, который знает, как вставлять сопоставления сервлетов в файл web.xml повторяемым образом каждый раз. время запуска файла сборки. Вместо этого мы использовали XML-сущность include, чтобы сгенерированные отображения сервлетов входили в новый файл каждый раз, когда запускается файл сборки, и этот файл отображений сервлетов можно вставлять в ваш файл web.xml с помощью механизма включения XML-сущностей. Чтобы использовать его, WEB-INF / web.xml вашего веб-приложения должен иметь специальное объявление сущности в верхней части файла, а также ссылку на сущность в содержимом файла web.xml, где вы хотите, чтобы файл сопоставления сервлета был включен. Вот как выглядит пустой файл web.xml webapp в 2.5 сервлета с этими изменениями:

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

Убедитесь, что файл web.xml вашего веб-приложения имеет встроенный DTD (тег DOCTYPE) в верхней части файла и объявление схемы веб-приложения servlet 2.5 под ним. Затем, куда бы вы ни захотели вставить сгенерированные отображения сервлетов в ваш файл web.xml, поместите ссылку на сущность & jspc-webxml; , Помните, что ссылка на сущность начинается с амперсанда (&), затем имеет имя сущности и заканчивается точкой с запятой (;).

Чтобы использовать файл сборки, просто отредактируйте его и установите для всех свойств в верхней части значения, соответствующие вашим настройкам, а затем запустите его так:

$ ant -f pre-compile-jsps.xml

1 голос
/ 16 февраля 2010

Если вы воспользуетесь решением, упомянутым Даффимо, указывающим на блог Винни Карпентер, у меня есть совет. Была одна область, из-за которой мой контейнер зависал на неопределенное время при обращении к localhost (в частности, в методе private connect ()). Мой обходной путь был следующим:

    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);
        }
    }

Установка тайм-аута и игнорирование SocketTimeoutException сработали (хотя, по общему признанию, это не лучшее решение). Кроме того, использование этой процедуры означает, что вам нужно будет указать JSP в web.xml. Этого было достаточно для моих нужд.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...