Javalite框架-定位现有FreeMarker模板的问题

Javalite框架-定位现有FreeMarker模板的问题,java,freemarker,embedded-jetty,javalite,Java,Freemarker,Embedded Jetty,Javalite,我正在开发一个简单的web应用程序,它提供RestFul API来管理多个资源 我使用的是java标准版-openjdk版本“1.8.0_191和以下依赖项: javalite-common-2.3-SNAPSHOT.jar activejdbc-2.3-SNAPSHOT.jar activeweb-2.3-SNAPSHOT.jar activeweb-testing-2.3-SNAPSHOT.jar freemarker-2.3.28.jar 我对web服务器使用embeddedjetty

我正在开发一个简单的web应用程序,它提供RestFul API来管理多个资源

我使用的是java标准版-
openjdk版本“1.8.0_191
和以下依赖项:

  • javalite-common-2.3-SNAPSHOT.jar
  • activejdbc-2.3-SNAPSHOT.jar
  • activeweb-2.3-SNAPSHOT.jar
  • activeweb-testing-2.3-SNAPSHOT.jar
  • freemarker-2.3.28.jar
我对web服务器使用embedded
jetty v9.4.1
,整个项目打包为带有依赖项的jar,并使用以下命令运行:

java-Dconfig=/etc/project/config.properties-jar jarname.jar

web应用程序设计为仅提供JSON,所有FreeMarker模板都构造JSON消息。以下是我的FreeMarker配置类:

public class FreeMarkerConfig extends AbstractFreeMarkerConfig {
    @Override
    public void init() {
        // this is to override a strange FreeMarker default processing of numbers
        Configuration config = this.getConfiguration();
        config.setNumberFormat("0.##");

        config.setClassicCompatible(true);
        config.setClassForTemplateLoading(this.getClass(), "webapp/WEB-INF/views");
    }
}
打包后,jar内部的结构如下所示(这是一个只有一个资源的简化版本):

大多数情况下,一切似乎都正常运行,没有任何问题。但在某个时候发生了一些事情,FreeMarker无法找到以前多次提供的模板

我无法在localhost上重现该行为,因此无法调试它

它在服务器上运行时发生过几次。我唯一观察到的情况是,它发生在几个空闲小时后-即几个小时内没有请求,下一个请求失败,因为FreeMarker无法找到所需的模板。下面是请求
/offices
时引发的确切异常:


2019-06-24 15:22:50 - INFO  LazyList:164 - {"sql":"SELECT * FROM offices  ORDER BY id  LIMIT 20  OFFSET 0 ","params":[],"duration_millis":2,"cache":"miss"}
2019-06-24 15:22:50 - INFO  DB:164 - {"sql":"SELECT COUNT(*) FROM offices","params":[],"duration_millis":0}
2019-06-24 15:22:50 - INFO  FreeMarkerTemplateManager:81 - Rendering template: '/offices/index.ftl' without layout.
2019-06-24 15:22:50 - INFO  FreeMarkerTemplateManager:81 - Rendering template: '/shared/message.ftl' without layout.
2019-06-24 15:22:50 - INFO  RequestDispatcher:360 - {"controller":"app.controllers.OfficesController","duration_millis":15,"remote_ip":"127.0.0.1","method":"GET","action":"index","error":"Failed to render template: '/shared/message.ftl' without layout.  Template not found for name \\\"/shared/message.ftl\\\".\\nThe name was interpreted by this TemplateLoader: WebappTemplateLoader(subdirPath=\\\"/WEB-INF/views/\\\", servletContext={contextPath=\\\"\\\", displayName=\\\"activeweb\\\"}).","url":"http://127.0.0.1:5050/offices","status":404}
2019-06-24 15:22:50 - INFO  FreeMarkerTemplateManager:81 - Rendering template: '/system/404.ftl' with layout: '/layouts/default_layout.ftl'.
2019-06-24 15:22:50 - ERROR RequestDispatcher:290 - ActiveWeb internal error:
org.javalite.activeweb.ViewMissingException: Failed to render template: '/system/404.ftl' with layout: '/layouts/default_layout.ftl'.  Template not found for name "/system/404.ftl".
The name was interpreted by this TemplateLoader: WebappTemplateLoader(subdirPath="/WEB-INF/views/", servletContext={contextPath="", displayName="activeweb"}).
  at org.javalite.activeweb.freemarker.FreeMarkerTemplateManager.merge(FreeMarkerTemplateManager.java:109)
  at org.javalite.activeweb.RenderTemplateResponse.doProcess(RenderTemplateResponse.java:88)
  at org.javalite.activeweb.ControllerResponse.process(ControllerResponse.java:67)
  at org.javalite.activeweb.RequestDispatcher.renderSystemError(RequestDispatcher.java:283)
  at org.javalite.activeweb.RequestDispatcher.doFilter(RequestDispatcher.java:219)
  at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1613)
  at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:541)
  at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
  at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)
  at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
  at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:190)
  at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1584)
  at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:188)
  at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1228)
  at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:168)
  at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:481)
  at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1553)
  at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:166)
  at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1130)
  at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
  at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
  at org.eclipse.jetty.server.Server.handle(Server.java:564)
  at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:320)
  at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:251)
  at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)
  at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:112)
  at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)
  at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:672)
  at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:590)
  at java.lang.Thread.run(Thread.java:748)
如有需要,可提供其他详细信息

是什么导致了这样的问题?当一切看起来都在运行时,FreeMaker突然无法找到以前提供的没有任何问题的模板

任何可能有助于调试问题的建议都将不胜感激


谢谢!

经过更详细的调查,jetty似乎从jar中提取了FreeMarker模板,并将它们放在
/tmp
文件夹中

/tmp/jetty-----.dir

例如:
jetty-0.0.0-5050-webapp-u-any-35239075401795634.dir

基于Unix的操作系统有清理
/tmp
文件夹的策略,并且在删除文件夹后-显然找不到模板

解决方案是将jetty的WebAppContext配置为对此类数据使用另一个目录。这可以通过
setTempDirectory
方法完成:

String webViewsPath = Launcher.class.getResource("/webapp").toString();
WebAppContext webapp = new WebAppContext(webViewsPath, "/");
webapp.setTempDirectory(new File("/data/templates"));
server.setHandler(webapp);
jetty临时目录的更多信息可在此处找到:

这可能与Freemarker有关,而不是与JavaLite有关。在构建基于JavaLite的系统的10年中,我们从未遇到视图从运行时消失的情况。然而,我们也从未在Jetty中运行过嵌入的JavaLite。能否请您在Tomcat上试验并将其作为WAR文件部署,然后运行一段时间,看看是否遇到此问题?至少你会消除嵌入式Jetty-也许Freemarker在那里感觉不太好。你可以看看Jetty是否正在将文件从WAR文件扩展到文件系统,并以某种方式清除它们?为什么不在你的应用程序中添加调试日志记录,记录模板工作时的实际来源,因此在出现错误时,您可以手动检查文件是否仍然存在。另一个疯狂的想法是,也许jetty将war文件扩展到删除文件的临时目录中?请注意,您的FreeMarker配置显然已被覆盖,因为实际的
TemplateLoader
WebappTemplateLoader
(来自错误消息),而不是您配置的
ClassTemplateLoader
。但这当然不能解释为什么应用程序会中断…(正如@ipolevoy所说,通常是
tmp
dir被计划的作业清除。)@ipolevoy,@ddekany您的评论真的很有帮助。通过快速运行调试级日志,我发现模板是从
/tmp
中的一个文件夹中提供的,看起来是这样的:
/tmp/jetty-0.0.0.0-5050-webapp-513;-any-1900243345654889594.dir
。运行项目的服务器似乎有一个针对
/tmp
文件夹正在删除模板。将
WebAppContext
tempDirectory
配置为在
/tmp
外部存储文件解决了此问题。谢谢!
String webViewsPath = Launcher.class.getResource("/webapp").toString();
WebAppContext webapp = new WebAppContext(webViewsPath, "/");
webapp.setTempDirectory(new File("/data/templates"));
server.setHandler(webapp);