我可以在 EJB 3 容器内的类路径中动态发现 xml 文件吗?
背景:
我们项目的组件之一使用 spring 运行。一些 SQL 代码是根据给定的 XML spring 配置动态生成的。
起初,将所有 XML 配置存储在类路径上的同一个包中(然后在调用服务时将其作为资源加载)是可以的,但随着时间的推移,我们最终会得到大量配置。是时候将配置分成不同的命名空间了。
目标
我想要的是,给定类路径上的起始包,递归地遍历目录结构并动态发现任何 spring XML 文件。 (这样当添加新的配置/包时,服务仍然可以找到这些文件)。
问题
当我在 EJB 容器外运行时,通过使用 Thread.getContextClassloader().getResource(myBasePackage) ,然后获取 File 对象并使用它在文件系统上遍历树。我知道,它很笨重,但它仍然是类路径相关的,而且它有效。
但是,您无法在 EJB 容器内执行此操作(您根本无法与文件系统交互),因此我不得不使用相当烦人的解决方法,其中我维护一个要搜索的硬编码包列表。
问题
是否有一种方法(在 EJB 容器内运行)动态遍历类路径(从给定的起始位置)搜索任意资源?
Background:
One of the components of our project operates using spring. Some SQL code is dynamically generated, based on a given XML spring configuration.
At first it was fine to store all the XML configurations in the same package on the classpath, (and then load it as a resource when the service is called) but over time we ended up with a large number of configurations. It came time to separate the configurations into different namespaces.
The Goal
What I want is, given a starting package on the classpath, to recursively walk the directory structure and discover any spring XML files dynamically. (So that as new configurations / packages are added, the files will still be found by the service).
The Problem
I was able to accomplish my goal fine when running outside an EJB container by using Thread.getContextClassloader().getResource(myBasePackage)
, then getting a File object and using it to walk the tree on the filesystem. Clunky, I know, but it was still classpath relative and it worked.
However, you cannot do this inside an EJB container (you can't interact with the filesystem at all), so I had to use the rather annoying workaround in which I maintain a list of hardcoded packages to search.
The Question
Is there a way (running inside an EJB container) to dynamically walk the classpath (from a given starting location) searching for arbitrary resources?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
简短的回答:在遵守 EJB 规范的情况下不会。因为规范设想容器在各种非标准情况下运行,所以它并没有使这成为可能。
更长的答案:由于您不是动态创建这些资源,因此我会编写一个例程,在构建时为您提供所有资源的列表,并将它们放入您的 EJB 知道如何引用的动态生成的文件中。因此,您基本上创建了一个包和文件的目录列表,您可以在一个主文件中引用的 EJB 中加载这些包和文件。
Spring 答案:Spring 支持在类路径上查找资源,尽管我不知道这在 EJB 上下文中效果如何(并且我怀疑它是否符合 EJB,但我没有检查过)。一些细节在这里。
Short answer: Not while staying in compliance with the EJB spec. Because the spec envisions containers running in all kinds of non-standard situations, it does not make this possible.
Longer answer: Since you are not creating these resources dynamically, I would write a routine that gives you a list of all of the resources at build time and puts them in a dynamically generated file that your EJB knows how to reference. So you basically create a directory listing of packages and files that you can load in the EJB that are referenced in one master file.
Spring answer: Spring supports finding resources on the classpath, although I have no idea how well this works in the EJB context (and I doubt its EJB compliant, but I haven't checked). Some details here.
免责声明:正如已经指出的,不建议在类路径中创建资源,并且根据 EJB 容器明确禁止创建资源。这可能会给您带来很多问题,因为容器可能会将您的资源分解到另一个文件夹中,甚至在整个集群中复制资源(如果是这种情况)。为了动态创建资源,您必须创建一个自定义类加载器。所以,我永远不会这样做。直接访问文件系统比访问类路径更好。如果您使用远程文件系统+文件锁,它就不那么难看了,并且最终是集群安全的。
如果即使在我解释之后您仍然想使用类路径,您可以尝试执行以下操作:通过
从基础包开始枚举所有出现的
情况来获取类加载器每个 URL 通常是文件链接 (file:///home /scott/.../MyResource.properties)或 jar 链接(file:///lib.jar!/com/domain/MyResource.properties)。您必须检查 URL 中的模式。使用它,使用普通的 java API 枚举文件夹的内容并找到子包。继续操作,直到扫描完所有包裹。
请参阅下面的课程(很快将与我的开源项目一起发布)。它实现了一个类路径扫描器,您可以在选择器中传递该扫描器。它的工作方式就像一个访客。这是我为你做的工作,如果没有,请从中获取想法。请参阅最后的示例注释选择器。
DISCLAIMER: As already pointed out, creating resources in the classpath is not recommended and depending on the EJB container explicitly forbidden. This may cause you a lot of problems because containers may explode your resources into another folder or even replicate the resources throughout the cluster (if thats the case). In order to create resources dynamically you have to create a custom classloader. So, I would never do it. It is better to access the filesystem directly than the classpath. It is less ugly and eventually cluster-safe if you use a remote filesystem + file locks.
If even after all I explained you still want to play with the classpath, you can try to do something like: get the classloader via
Starting from a base package enumerate all occurrences
Each URL is generally either a file link (file:///home/scott/.../MyResource.properties) or a jar link (file:///lib.jar!/com/domain/MyResource.properties). You have to check the pattern in the URL. Using that, enumerate the contents of the folder using the normal java API and find the subpackages. Proceed until you have scanned all packages.
See the class below (will be released with an open-source project of mine soon). It implemens a classpath scanner that you can pass in a selector. It works like a visitor. It my work for you, if not, get ideas from it. See the sample annotation selector at the end.