I got a preliminary compilation to work either during server startup (no need to use JspC, it’s easier to build file) and during build (much faster server startup time). I register received servlets dynamically, so you do not need to manually modify any files if you add / remove JSPs.
When starting the server
Use ServletRegistration.Dynamic to register a JSP_SERVLET_CLASS Servlet for each JSP. Use initParameter jspFile to set the JSP file name ( ref )
eg. for SpringBoot in ServletContextInitializer ( ref ):
@Bean public ServletContextInitializer preCompileJspsAtStartup() { return servletContext -> { getDeepResourcePaths(servletContext, "/WEB-INF/jsp/").forEach(jspPath -> { log.info("Registering JSP: {}", jspPath); ServletRegistration.Dynamic reg = servletContext.addServlet(jspPath, Constants.JSP_SERVLET_CLASS); reg.setInitParameter("jspFile", jspPath); reg.setLoadOnStartup(99); reg.addMapping(jspPath); }); }; } private static Stream<String> getDeepResourcePaths(ServletContext servletContext, String path) { return (path.endsWith("/")) ? servletContext.getResourcePaths(path).stream().flatMap(p -> getDeepResourcePaths(servletContext, p)) : Stream.of(path); }
At build time
Create Java source files for each JSP and web.xml with their servlet mappings using JspC ( ref ).
Then register them using ServletContext (by parsing web.xml using Tomcat WebXmlParser , e.g. for SpringBoot:
@Value("classpath:precompiled-jsp-web.xml") private Resource precompiledJspWebXml; @Bean public ServletContextInitializer registerPreCompiledJsps() { return servletContext -> {
Example Maven configuration for creating and compiling JSP classes and creating precompiled-jsp-web.xml :
<dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-catalina-ant</artifactId> <version>8.0.32</version> <scope>provided</scope> </dependency> <plugin> <artifactId>maven-antrun-plugin</artifactId> <version>1.8</version> <executions> <execution> <id>precompile-jsp-generate-java</id> <phase>compile</phase> <goals> <goal>run</goal> </goals> <configuration> <tasks> <echo message="Precompiling JSPs"/> <property name="compile_classpath" refid="maven.compile.classpath"/> <property name="target_dir" value="${project.basedir}/generated-sources/jspc" /> <path id="jspc_classpath"> <path path="${compile_classpath}"/> </path> <typedef resource="org/apache/catalina/ant/catalina.tasks" classpathref="jspc_classpath"/> <mkdir dir="${target_dir}/java"/> <mkdir dir="${target_dir}/resources"/> <jasper validateXml="false" uriroot="${project.basedir}/src/main/webapp" compilertargetvm="1.8" compilersourcevm="1.8" failonerror="true" javaencoding="UTF-8" webXml="${target_dir}/resources/precompiled-jsp-web.xml" outputDir="${target_dir}/java/" > </jasper> <javac srcdir="${target_dir}/java" destdir="${project.build.outputDirectory}" classpathref="jspc_classpath" fork="true"/> <copy todir="${project.build.outputDirectory}"> <fileset dir="${target_dir}/resources"/> </copy> </tasks> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> <executions> <execution> <id>add-precompiled-jsp-java-sources</id> <phase>generate-sources</phase> <goals><goal>add-source</goal></goals> <configuration> <sources> <source>${project.basedir}/generated-sources/jspc/java</source> </sources> </configuration> </execution> <execution> <id>add-precompiled-jsp-resources</id> <phase>generate-resources</phase> <goals><goal>add-resource</goal></goals> <configuration> <resources> <resource> <directory>${project.basedir}/generated-sources/jspc/resources</directory> </resource> </resources> </configuration> </execution> </executions> </plugin>
paulcm
source share