JSP 默认在首次被请求时才会编译,结果就是首次请求时响应异常缓慢。下面的办法可实现应用启动时完成 JSP 预编译。

// ...

import org.springframework.boot.web.servlet.ServletContextInitializer;

import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;

import static org.apache.catalina.core.Constants.JSP_SERVLET_CLASS;

// ...

@Bean("jspPreCompileServletContextInitializer")
public ServletContextInitializer preCompileJspsOnStartup() {
	return servletContext -> getDeepResourcePaths(servletContext, "/views/")
			.filter(jspPath -> StringUtils.endsWith(jspPath, ".jsp"))
			.forEach(jspPath -> {
				ServletRegistration.Dynamic servletRegistration =
						servletContext.addServlet(jspPath, JSP_SERVLET_CLASS);

				servletRegistration.setInitParameter("development", "false");
				servletRegistration.setInitParameter("jspFile", jspPath);
				servletRegistration.setLoadOnStartup(1);
				servletRegistration.addMapping(jspPath);
			});
}

private Stream<String> getDeepResourcePaths(ServletContext servletContext, String path) {
	return path.endsWith("/") ? servletContext.getResourcePaths(path).stream()
			.flatMap(p -> getDeepResourcePaths(servletContext, p)) : Stream.of(path);
}

注意:

  • development参数表示以开发模式运行(将检查 JSP 文件是否有修改),tomcat默认为true,配合modificationTestInterval参数可以改变检查频率,此处将其关闭。
  • JSP 的编译是在JspServlet初始化时进行的,因此setLoadOnStartup(1)JspServlet在启动时初始化,就可以实现 JSP 文件在启动时就完成编译而不是首次被请求时。

另外,还可用使用 JSPC 在项目编译期实现 JSP 预编译。