2

我有一个正在开发的 Grails 2.1 应用程序,并且我有一个正在调用Thread.currentThread().contextClassLoader.getResource(fileName)以加载配置文件的服务grails-app/conf(不过,我希望位置无关紧要)。

它工作得很好,除了我必须重新启动 grails 应用程序来加载对配置文件的更改。我真的很希望每次请求资源时都能读取文件内容,至少在开发过程中是这样。

另外,如果可以避免的话,我想避免编写自己的缓存系统。解决方案越简单越好。

我的问题似乎与速度类似,但使用getClass().getClassLoader().getResource(path).openStream()似乎不起作用。

编辑:我想我可能遗漏了一个重要的细节。我正在检索的资源是非静态的。我正在使用 grails 模板引擎将值注入到资源中,如下所示:

Map bindings = [keys: 'values']
new SimpleTemplateEngine().createTemplate(resource).make(bindings).toString()

使用我的调试器,我发现资源文本没有改变,但知道上述内容可能会改变潜在的答案。

编辑#2:我尝试使用 URLConnection.setUseCaches(false) ,但没有运气:

URLConnection connection = Thread.currentThread().contextClassLoader.getResource(path).openConnection()
connection.setUseCaches(false)
connection.connect()
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))
String content = reader.readLines().join('\n')
reader.close()
4

4 回答 4

3

If you're using a resource in this manner, you might consider moving it out of grails-app/conf and into /web-app.

When running grails run-app, a cached version of an exploded war is actually running in a container with some outside magic monitoring various paths for changes and re-compiling and re-copying updated files similar to how one might manually hot-swap .class files and other resources.

This monitoring happens out of the box for all files in /web-app. Once the files are there, you can use the ServletContext to get a handle to the file in question. For example, you might do something like:

def templateFile = new File(ServletContextHolder.servletContext.getRealPath('/templates/fileName.gsp')).text

and pass that to your templating engine. For environments that lock down the file system (e.g. Heroku), the getRealPath method will likely not work. You can, alternatively, use something like:

import org.apache.commons.io.IOUtils
def template =  IOUtils.toString(ServletContextHolder.servletContext.getResourceAsStream('/templates/fileName.gsp'), "UTF-8")

The downsides to this approach:

  • You'll need access to the ServletContext which will require you to have a container loaded. Therefore, no unit testing on this piece of coding; you'll want an integration test instead.
  • Putting resources like this in /web-app will make them public. Alternatively, you could place them in /web-app/WEB-INF if privacy is a concern.

Hope this helps!

于 2012-08-15T04:43:12.413 回答
1

Just a thought, but Grails services are normally singletons. If you want the file re-read on every request, you might try changing the scope to prototype.

于 2012-08-15T02:03:57.527 回答
1

您可以使用 Spring 的 ResourceUtils 来执行此操作吗? http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/util/ResourceUtils.html

它看起来像 ResourceUtils.getFile("classpath:path/to/file.xyz")

于 2012-08-14T23:03:15.163 回答
1

getClass().getClassLoader().getResource(path)返回一个 URL 对象,因此缓存可能由URL/执行URLConnection

在您的应用程序启动时尝试使用URLConnection.setDefaultUseCaches (出于性能原因,可能仅在开发环境中)。(false)这也可以使用该setUseCaches()方法在每个 URLConnection 的基础上进行设置。

于 2012-08-15T00:28:04.290 回答