Java 我可以在EJB3容器内的类路径中动态发现xml文件吗?
背景: 我们项目的一个组件使用spring进行操作。一些SQL代码是基于给定的XMLSpring配置动态生成的 起初,将所有XML配置存储在类路径上的同一个包中是不错的(然后在调用服务时将其作为资源加载),但随着时间的推移,我们最终得到了大量的配置。现在是将配置分离到不同名称空间的时候了 目标 我想要的是,给定类路径上的起始包,递归地遍历目录结构并动态发现任何SpringXML文件。(这样,在添加新配置/包时,服务仍会找到这些文件) 问题 通过使用Java 我可以在EJB3容器内的类路径中动态发现xml文件吗?,java,xml,ejb-3.0,classpath,Java,Xml,Ejb 3.0,Classpath,背景: 我们项目的一个组件使用spring进行操作。一些SQL代码是基于给定的XMLSpring配置动态生成的 起初,将所有XML配置存储在类路径上的同一个包中是不错的(然后在调用服务时将其作为资源加载),但随着时间的推移,我们最终得到了大量的配置。现在是将配置分离到不同名称空间的时候了 目标 我想要的是,给定类路径上的起始包,递归地遍历目录结构并动态发现任何SpringXML文件。(这样,在添加新配置/包时,服务仍会找到这些文件) 问题 通过使用Thread.getContextClasslo
Thread.getContextClassloader().getResource(myBasePackage)
,然后获取一个文件对象并使用它在文件系统上遍历树,在EJB容器外部运行时,我能够很好地完成我的目标。笨重,我知道,但它仍然是类路径相关的,而且它工作正常
但是,您不能在EJB容器中执行此操作(您根本无法与文件系统交互),因此我不得不使用相当烦人的解决方法,在该方法中,我维护了一个要搜索的硬编码包列表
问题
有没有一种方法(在EJB容器中运行)可以动态地遍历类路径(从给定的起始位置)来搜索任意资源?简短回答:在遵守EJB规范的情况下没有。因为规范设想容器在各种非标准情况下运行,所以它不可能做到这一点 更详细的回答:因为您不是动态创建这些资源,所以我将编写一个例程,在构建时为您提供所有资源的列表,并将它们放入EJB知道如何引用的动态生成的文件中。因此,您基本上创建了一个目录列表,其中列出了可以加载到EJB中的包和文件,这些包和文件在一个主文件中引用
Spring回答:Spring支持在类路径上查找资源,尽管我不知道这在EJB上下文中的效果如何(我怀疑它是否兼容EJB,但我没有检查)。一些细节。免责声明:如前所述,不建议在类路径中创建资源,这取决于明确禁止的EJB容器。这可能会给您带来很多问题,因为容器可能会将您的资源分解到另一个文件夹中,甚至在整个集群中复制资源(如果是这样的话)。为了动态创建资源,您必须创建一个自定义类加载器。所以,我永远不会这么做。直接访问文件系统比访问类路径更好。如果您使用远程文件系统+文件锁,它就不那么难看了,而且最终是集群安全的 即使在我解释了所有这些之后,您仍然希望使用类路径,那么您可以尝试这样做:通过
ClassLoader cld = Thread.currentThread().getContextClassLoader();
从基本包开始枚举所有实例
Enumeration<URL> basePackageUrls = cld.getResources(basePackagePath);
枚举basePackageUrls=cld.getResources(basePackagePath);
每个URL通常是一个文件链接(file:///home/scott/.../MyResource.properties)或者一个jar链接(file:///lib.jar!/com/domain/MyResource.properties)。您必须检查URL中的模式。使用该方法,使用普通JavaAPI枚举文件夹的内容并查找子包。继续,直到扫描完所有包
请参阅下面的课程(很快将与我的开源项目一起发布)。它实现了一个类路径扫描器,您可以将其传入选择器。它就像一个访客。这是我为你做的工作,如果不是,从中获取想法。请参见末尾的示例注释选择器
public class ClasspathScanner
{
private static final Log log = LogFactory.getLog(ClasspathScanner.class);
private static final String JAR_FILE_PATTERN = ".jar!";
private ClassSelector selector;
private Set<Class<?>> classes;
// PUBLIC METHODS ------------------------------------------------------------------------------
public synchronized Set<Class<?>> scanPackage(String basePackage, ClassSelector selector)
throws Exception
{
if (selector == null)
{
throw new NullPointerException("Selector cannot be NULL");
}
this.selector = selector;
this.classes = new HashSet<Class<?>>();
Set<Class<?>> aux;
try
{
scanClasses0(basePackage);
aux = this.classes;
}
finally
{
this.selector = null;
this.classes = null;
}
return aux;
}
// HELPER CLASSES ------------------------------------------------------------------------------
private void scanClasses0(String basePackage)
throws IOException, ClassNotFoundException, FileNotFoundException
{
File packageDirectory = null;
ClassLoader cld = getLoader();
String basePackagePath = basePackage.replace('.', '/');
Enumeration<URL> basePackageUrls = cld.getResources(basePackagePath);
if (basePackageUrls == null || !basePackageUrls.hasMoreElements())
{
throw new ClassNotFoundException("Base package path not found: [" + basePackagePath
+ "]");
}
while (basePackageUrls.hasMoreElements())
{
String packagePath = basePackageUrls.nextElement().getFile();
if (packagePath.contains(JAR_FILE_PATTERN))
{
scanJarFile(basePackagePath, packagePath);
}
else
{
packageDirectory = new File(packagePath);
scanDirectory(basePackage, packageDirectory);
}
}
}
private void scanDirectory(String packageName, File packagePath)
throws ClassNotFoundException, FileNotFoundException
{
if (packagePath.exists())
{
File[] packageFiles = packagePath.listFiles();
for (File file : packageFiles)
{
if (file.isFile() && file.getName().endsWith(".class"))
{
String fullFileName = packageName + '.' + file.getName();
checkClass(fullFileName);
}
else if (file.isDirectory())
{
scanDirectory(packageName + "." + file.getName(), file);
}
}
}
else
{
throw new FileNotFoundException(packagePath.getPath());
}
}
private void scanJarFile(String basePackagePath, String jarFileUrl)
throws IOException, ClassNotFoundException
{
String jarFilePath = jarFileUrl.substring("file:".length(), jarFileUrl
.indexOf(JAR_FILE_PATTERN)
+ JAR_FILE_PATTERN.length() - 1);
log.debug("URL JAR file path: [" + jarFilePath + "]");
jarFilePath = URLDecoder.decode(jarFilePath, "UTF-8");
log.debug("Decoded JAR file path: [" + jarFilePath + "]");
JarFile jar = new JarFile(new File(jarFilePath));
for (Enumeration<JarEntry> jarFiles = jar.entries(); jarFiles.hasMoreElements();)
{
JarEntry file = jarFiles.nextElement();
String fileName = file.getName();
if (!file.isDirectory() && fileName.endsWith(".class")
&& fileName.startsWith(basePackagePath))
{
String className = fileName.replace('/', '.');
checkClass(className);
}
}
}
private void checkClass(String fullFilePath) throws ClassNotFoundException
{
String className = fullFilePath.substring(0, fullFilePath.length() - 6);
Class<?> c = getLoader().loadClass(className);
if (selector.select(c))
{
classes.add(c);
}
}
private ClassLoader getLoader()
{
ClassLoader loader = Thread.currentThread().getContextClassLoader();
if (loader == null)
{
loader = getClass().getClassLoader();
}
return loader;
}
// INNER CLASSES -------------------------------------------------------------------------------
public interface ClassSelector
{
boolean select(Class<?> clazz);
}
public static class AnnotatedClassSelector implements ClassSelector
{
private final Class<? extends Annotation>[] annotations;
public AnnotatedClassSelector(Class<? extends Annotation>... annotations)
{
this.annotations = annotations;
}
public boolean select(Class<?> clazz)
{
for (Class<? extends Annotation> ac : annotations)
{
if (clazz.isAnnotationPresent(ac))
{
return true;
}
}
return false;
}
}
}
公共类类路径扫描程序
{
私有静态最终日志日志=LogFactory.getLog(ClasspathScanner.class);
私有静态最终字符串JAR_FILE_PATTERN=“.JAR!”;
私有类选择器;
private Set>scanPackage(字符串basePackage,类选择器)
抛出异常
{
if(选择器==null)
{
抛出新的NullPointerException(“选择器不能为NULL”);
}
this.selector=选择器;
this.classes=newhashset>aux;
尝试
{
scanClasses0(基本包);
aux=这个类;
}
最后
{
this.selector=null;
this.classes=null;
}
返回aux;
}
//助手类------------------------------------------------------------------------------
私有void扫描类0(字符串basePackage)
抛出IOException、ClassNotFoundException、FileNotFoundException
{
File packageDirectory=null;
ClassLoader cld=getLoader();
字符串basePackagePath=basePackage.replace('.','/');
枚举basePackageUrls=cld.getResources(basePackagePath);
if(basePackageUrls==null | |!basePackageUrls.hasMoreElements())
{
抛出新的ClassNotFoundException(“未找到基本包路径:[”+basePackagePath
+ "]");
}
while(basePackageUrls.hasMoreElements())
{
字符串packagePath=basePackageUrls.nextElement().getFile();
if(packagePath.contains(JAR\u文件\u模式))
{
scanJarFile(basePackagePath,packagePath);
}
其他的
{
packageDirectory=新文件(packagePath);
扫描目录(basePackage、packageDirectory);
}
}
}
私有void扫描目录(字符串packageName、文件packagePath)
抛出ClassNotFoundException、FileNotFoundException
{
if(packagePath.exists())
{
File[]packageFiles=packagePath.listFiles();