如何让Jetty动态加载“静态”页面

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

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

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

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

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

故障排除Windows上的锁定文件(来自Jetty wiki)有说明。

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

你会在网上找到一些建议,包括

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

虽然这是一个老问题,但我发现这篇文章非常有用,简而言之,只需将配置更改为

   org.mortbay.jetty jetty-maven-plugin    8080     

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

Jetty 9.2文档提供了一个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(内存文件映射),因此锁定Windows操作系统上的文件 。 这是一个已知问题,可以找到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上提供静态文件,您可以编辑它们。

在webdefault.xml中将false设置为useFileMappedBuffer对我来说不起作用(Jetty 8.1.10.v20130312)。 幸运的是,将maxCachedFiles设置为0(也在webdefault.xml中)就可以了。

我也有这个问题。

而且我不想创建任何其他类并搞乱web.xml

所以这是你可以做的:

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

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

2)把这些东西放进去:

    org.eclipse.jetty.servlet.Default.useFileMappedBuffer false   

3)这是你的docker配置:

  org.eclipse.jetty jetty-maven-plugin   localhost 8801   /${project.artifactId}  ${project.basedir}/jetty/jetty-config.xml   

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

玩的开心 :)

与@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的深处。 但是,如上所述为属性名称添加前缀,则首选此值。

使用嵌入式Jetty 8.1.10时,’useFileMappedBuffer = false’设置不适用于任何模式。 我读了DefaultServlet的代码,它读取了属性但它没有用于任何东西。

相反,我查看了缓冲区创建的配置位置,发现我可以inheritanceSelectChannelConnector以获得Continuation的好处,但不会在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. * 

* 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。

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

它可能是持有它的浏览器。

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

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