【问题标题】:How to make Jetty dynamically load "static" pages如何让 Jetty 动态加载“静态”页面
【发布时间】:2008-10-08 18:57:28
【问题描述】:

我正在构建 Java Web 应用程序,我讨厌传统的“代码-编译-部署-测试”循环。我想输入一个微小的更改,然后立即查看结果,而无需编译和部署。

幸运的是,Jetty 非常适合这个。它是一个纯 Java 网络服务器。它带有一个非常好的maven plugin,它可以让您直接从构建树中启动 Jetty 读取 - 无需打包战争文件或部署。它甚至有一个 scanInterval 设置:将其设置为非零值,它会监视您的 java 文件和各种配置文件的更改,并在您进行更改几秒钟后自动重新部署。

只有一件事让我远离涅槃。我的 src/main/webapp 目录中有 javascript 和 css 文件,这些文件只是由 Jetty 提供的。我希望能够编辑 这些 并在我在浏览器中刷新页面时显示更改。不幸的是,Jetty 将这些文件保持打开状态,因此我无法(在 Windows 上)在它运行时修改它们。

有谁知道如何让 Jetty 释放这些文件,以便我可以编辑它们,然后为后续请求提供编辑后的文件?

【问题讨论】:

    标签: java spring jetty


    【解决方案1】:

    Jetty 使用内存映射文件来缓冲静态内容,这会导致 Windows 中的文件锁定。尝试将useFileMappedBufferDefaultServlet 设置为false

    Troubleshooting Locked files on Windows (from the Jetty wiki) 有说明。

    【讨论】:

    • 谢谢!这正是我想要的。如果 stackoverflow 允许,我会将其标记为“已接受”的答案(我不确定为什么不允许)。
    • 我尝试了这些说明,经过一番摆弄(主要是弄清楚如何在我的 POM 中指定我正在使用自定义的 webdefault.xml 文件)后,我得到了它的工作。再次感谢。
    • 此答案不再适用于 Jetty 8。我在 8.1.9 和 8.1.10 中进行了测试,即使我确实在 Jetty 7 中使用了它。我将发布另一个答案以避免该问题在 Jetty 8.1.10 中,可能还有其他版本。
    • 不像@FUD那样使用nio更简单。
    【解决方案2】:

    虽然上面的答案之一完全适合通过 xml 配置码头,但如果您想在代码中配置此选项(对于嵌入式服务器),答案是不同的,并且在该页面上找不到。

    您会在网上找到许多建议,包括

    context.getInitParams().put("useFileMappedBuffer", "false");

    或覆盖 WebAppContext,或为 init 参数使用完全限定名称。这些建议都不适合我(使用 Jetty 7.2.2)。部分问题是需要在 WebAppContext 用于提供静态文件的 servlet 上设置 useFileMappedBuffer 选项,而不是在上下文中设置。

    最后我在一个简单的 ServletContextHandler 上做了这样的事情

    // Startup stuff
    final Server server = new Server(port);
    ServletContextHandler handler = new ServletContextHandler();
    handler.setResourceBase(path);
    
    SessionManager sm = new HashSessionManager();
    SessionHandler sh = new SessionHandler(sm);
    handler.setSessionHandler(sh);
    
    DefaultServlet defaultServlet = new DefaultServlet();
    ServletHolder holder = new ServletHolder(defaultServlet);
    holder.setInitParameter("useFileMappedBuffer", "false");
    handler.addServlet(holder, "/");
    
    server.setHandler(handler);
    server.start();
    server.join();
    

    【讨论】:

    • 正是我想要的!您有完整示例的链接吗?
    • 不怕,我通过反复试验找到了它,还没有找到其他人解释如何做到这一点。我有一个我自己创建的完整示例(执行 jsps、请求日志记录和配置一些 mimetypes 等),但如果您想要更多,我会在上面的示例中添加更多内容。
    • 新的例子很完美。我有类似的东西。如果我不能让它工作,我会问一个新问题。
    • 如果你在上下文中设置参数,你必须在键前面加上“org.eclipse.jetty.servlet.Default.”,所以这对我有用:webAppContext.setInitParameter("org. eclipse.jetty.servlet.Default.useFileMappedBuffer", "false");。使用 Jetty 8.1.4 为我工作。
    • 当我第一次写这段代码时,我看到网上有很多关于前缀参数和非前缀参数的参考。我都尝试了,只能让我展示的代码工作,但大概它在 7.2.2 和 8.1.4 之间发生了变化。感谢您的提醒。
    【解决方案3】:

    虽然这是一个老问题,但我发现this 的帖子很有帮助,简而言之,只需将您的配置更改为

                <plugin>
                    <groupId>org.mortbay.jetty</groupId>
                    <artifactId>jetty-maven-plugin</artifactId>
                    <configuration>
                    <connectors>
                        <connector implementation="org.eclipse.jetty.server.bio.SocketConnector">
                            <port>8080</port>
                        </connector>
                    </connectors>
                    </configuration>
                </plugin>
    

    这会禁用 Jetty 中的 NIO 支持(但对于简单情况的调试目的来说应该不是问题)。

    【讨论】:

    • 这很简单。我不想麻烦使用 useFileMappedB‌uffer 设置和 webdefault.xml。效果很好。
    • 根据GrepCodeorg.eclipse.jetty.server.bio.SocketConnector 类只存在于 Jetty 7 和 Jetty 8。
    【解决方案4】:

    Jetty 9.2 documentation 给出了一个 Jetty Embedded 示例,使用 ResourceHandler 而不是 servlet 来提供静态文件:

    // Create a basic Jetty server object that will listen on port 8080.  Note that if you set this to port 0
    // then a randomly available port will be assigned that you can either look in the logs for the port,
    // or programmatically obtain it for use in test cases.
    Server server = new Server(8080);
    
    // Create the ResourceHandler. It is the object that will actually handle the request for a given file. It is
    // a Jetty Handler object so it is suitable for chaining with other handlers as you will see in other examples.
    ResourceHandler resource_handler = new ResourceHandler();
    // Configure the ResourceHandler. Setting the resource base indicates where the files should be served out of.
    // In this example it is the current directory but it can be configured to anything that the jvm has access to.
    resource_handler.setDirectoriesListed(true);
    resource_handler.setWelcomeFiles(new String[]{ "index.html" });
    resource_handler.setResourceBase(".");
    
    // Add the ResourceHandler to the server.
    HandlerList handlers = new HandlerList();
    handlers.setHandlers(new Handler[] { resource_handler, new DefaultHandler() });
    server.setHandler(handlers);
    
    // Start things up! By using the server.join() the server thread will join with the current thread.
    // See "http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#join()" for more details.
    server.start();
    server.join();
    

    Jetty 使用 NIO(内存文件映射),因此使用了locks files on Windows operating systems。这是一个已知问题,可以为 servlet 找到许多解决方法。

    但是,由于此示例不依赖于 servlet,因此基于 webapp 参数(useFileMappedBuffer、maxCachedFiles)的相关答案不起作用。

    为了防止内存文件映射,需要添加如下配置行:

    resource_handler.setMinMemoryMappedContentLength(-1);
    

    注意:如 Javadoc 中所写(并由 nimrodm 注意到):the minimum size in bytes of a file resource that will be served using a memory mapped buffer, or -1 for no memory mapped buffers。然而,我得到了与值 Integer.MAX_VALUE 相同的行为。

    设置此参数后,您的 Jetty 可以在 Windows 上提供静态文件并且您可以对其进行编辑。

    【讨论】:

    • 这是唯一对我使用 Embedded Jetty 9 非常有用的解决方案,它使用各种处理程序,如带有 gzip 的 resource_handler。
    • Jetty 文档说将“-1”传递给 setMin..Length 应该禁用内存映射(就我个人而言,我还没有设法让它工作......)
    • @nimrodm:你是对的,因此我改进了答案。
    【解决方案5】:

    在 webdefault.xml 中将 false 设置为 useFileMappedBuffer NOT 对我有用(Jetty 8.1.10.v20130312)。 幸运的是,将 maxCachedFiles 设置为 0(也在 webdefault.xml 中)起到了作用。

    【讨论】:

    • 谢谢老兄!这种方法也适用于我。我正在使用 Jetty Embedded 8.1.9 WebAppContext root = new WebAppContext(); root.setInitParameter("org.eclipse.jetty.servlet.Default.maxCachedFiles", "0");使用 useFileMappedBuffer 什么也没发生
    【解决方案6】:

    我也有这个问题。

    而且我不想创建任何额外的类并弄乱 web.xml

    所以你可以这样做:

    假设您的项目是基于 maven 的并且(可以说)称为“my-web-app”

    1. 创建文件my-web-app/jetty/jetty-config.xml

    2. 把这些东西放进去:

      <?xml version="1.0" encoding="UTF-8"?>
      <Configure class="org.eclipse.jetty.webapp.WebAppContext">
         <Call name="setInitParameter">
           <Arg>org.eclipse.jetty.servlet.Default.useFileMappedBuffer</Arg>
           <Arg>false</Arg>
         </Call>
      </Configure>
      
    3. 这是您的码头配置:

      <plugin>
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>jetty-maven-plugin</artifactId>
          <configuration>
              <httpConnector>
                  <host>localhost</host>
                  <port>8801</port>
              </httpConnector>
              <webApp>
                  <contextPath>/${project.artifactId}</contextPath>
              </webApp>
              <contextXml>${project.basedir}/jetty/jetty-config.xml</contextXml>
          </configuration>
      </plugin>
      

    此解决方案将为您的 servlet-context 添加一个属性,该属性将禁用静态资源锁定。

    玩得开心:)

    【讨论】:

    • 谢谢!适用于 jetty-maven-plugin 9.3.10.v20160621!
    【解决方案7】:

    类似于@kybernetikos 的回答,但无需重新创建 DefaultServlet:

    // Startup stuff
    final Server server = new Server(port);
    WebAppContext webAppContext = new WebAppContext(path, "/")
    webAppContext.setInitParam(
            "org.eclipse.jetty.servlet.Default.useFileMappedBuffer", "false");
    
    server.setHandler(webAppContext);
    server.start();
    server.join();
    

    DefaultServlet 将寻找它自己的 useFileMappedBuffer 副本,该副本似乎设置在 Jetty 的深处。但是通过在属性名称前面加上上述前缀,这个值是首选的。

    【讨论】:

      【解决方案8】:

      使用嵌入式 Jetty 8.1.10 时,“useFileMappedBuffer=false”设置在任何模式下都不起作用。我阅读了DefaultServlet 的代码,它读取了属性,但它没有用于任何用途。

      相反,我查看了缓冲区创建的配置位置,发现我可以继承 SelectChannelConnector 以获得继续的好处,但无需在 Windows 上锁定文件。如果您只是使用org.mortbay.jetty.bio.SocketConnector,那么您将无法获得持续支持。

      这是我的例子:

      import org.eclipse.jetty.io.Buffers.Type;
      import org.eclipse.jetty.server.nio.SelectChannelConnector;
      
      /**
       * A Connector that has the advantages NIO, but doesn't lock files in Windows by
       * avoiding memory mapped buffers.
       * <p> 
       * It used to be that you could avoid this problem by setting "useFileMappedBuffer" as described in 
       * http://stackoverflow.com/questions/184312/how-to-make-jetty-dynamically-load-static-pages
       * However that approach doesn't seem to work in newer versions of jetty.
       * 
       * @author David Roussel
       * 
       */
      public class SelectChannelConnectorNonLocking extends SelectChannelConnector {
      
          public SelectChannelConnectorNonLocking() {
              super();
      
              // Override AbstractNIOConnector and use all indirect buffers
              _buffers.setRequestBufferType(Type.INDIRECT);
              _buffers.setRequestHeaderType(Type.INDIRECT);
              _buffers.setResponseBufferType(Type.INDIRECT);
              _buffers.setResponseHeaderType(Type.INDIRECT);
          }
      }
      

      我已经针对锁定问题对此进行了测试,它解决了这个问题。我还没有测试它是否适用于 Continuations。

      【解决方案9】:

      当使用带有 ResourceHandler 的 IntelliJ 和 Jetty 9 时,其中一种解决方案是编辑目标目录中的静态内容,而不是源文件。

      【讨论】:

      • 问题与IDE无关。
      【解决方案10】:

      很可能是浏览器在保留它。

      IE 内部:工具 |互联网选项 |临时 Internet 文件 > 设置,单击单选按钮“每次访问页面”。按确定。

      在此之前,请删除所有临时 Internet 文件。

      【讨论】:

      • 我认为他是在谈论 windows/jetty 锁定文件以使它们无法编辑。
      • 这个答案完全不正确。我会投反对票,但不能。
      猜你喜欢
      • 2017-05-06
      • 1970-01-01
      • 1970-01-01
      • 2013-09-03
      • 1970-01-01
      • 1970-01-01
      • 2012-02-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多