代码之家  ›  专栏  ›  技术社区  ›  Justin Standard

我可以在EJB3容器的类路径中动态地发现XML文件吗?

  •  1
  • Justin Standard  · 技术社区  · 15 年前

    背景:

    我们项目的一个组件使用Spring运行。一些SQL代码是基于给定的XML Spring配置动态生成的。

    起初,将所有XML配置存储在类路径上的同一个包中是可以的(然后在调用服务时将其作为资源加载),但随着时间的推移,我们最终得到了大量的配置。是时候将配置分为不同的名称空间了。

    目标

    我想要的是,在类路径上给定一个起始包,递归地遍历目录结构并动态地发现任何SpringXML文件。(这样,当添加新的配置/包时,服务仍然可以找到这些文件)。

    问题

    当我在EJB容器外运行时,我可以通过使用 Thread.getContextClassloader().getResource(myBasePackage) ,然后获取一个文件对象并使用它遍历文件系统上的树。笨重,我知道,但它仍然是类路径相关的,而且它起作用了。

    但是,您不能在EJB容器内执行此操作(您根本无法与文件系统交互),因此我必须使用相当烦人的解决方案,在该解决方案中维护要搜索的硬编码包列表。

    问题

    有没有一种方法(在EJB容器中运行)动态地遍历类路径(从给定的起始位置)来搜索任意资源?

    2 回复  |  直到 15 年前
        1
  •  1
  •   Yishai    15 年前

    简短的回答:在遵守EJB规范的同时,这是不可能的。因为规范设想容器在各种非标准情况下运行,所以它不可能做到这一点。

    更长的回答:由于您不是动态地创建这些资源,所以我将编写一个例程,它在构建时为您提供所有资源的列表,并将它们放在您的EJB知道如何引用的动态生成的文件中。因此,您基本上创建了一个包和文件的目录列表,您可以在一个主文件中引用的EJB中加载这些包和文件。

    Spring回答:Spring支持在类路径上查找资源,尽管我不知道它在EJB上下文中的工作情况如何(我怀疑它是否符合EJB,但我没有检查)。一些细节 here .

        2
  •  1
  •   Antonio    15 年前

    免责声明:正如已经指出的,不建议在类路径中创建资源,这取决于明确禁止的EJB容器。这可能会导致很多问题,因为容器可能会将您的资源分解到另一个文件夹中,或者甚至在整个集群中复制资源(如果是这样的话)。为了动态地创建资源,您必须创建一个自定义的类加载器。所以,我永远不会这么做。与类路径相比,直接访问文件系统更好。如果您使用一个远程文件系统+文件锁,它就不那么难看了,而且最终是群集安全的。

    即使我解释了这么多,如果你仍然想玩类路径,你可以尝试这样做:通过

    ClassLoader cld = Thread.currentThread().getContextClassLoader();
    

    从基本包开始枚举所有出现的次数

    Enumeration<URL> basePackageUrls = cld.getResources(basePackagePath);
    

    每个URL通常是文件链接(file:///home/scott/../myresource.properties)或JAR链接(file:///lib.jar!/com/domain/myresource.properties)。您必须检查URL中的模式。使用该方法,使用普通Java API枚举文件夹的内容并找到子包。继续,直到扫描完所有包。

    请参见下面的类(将很快与我的开源项目一起发布)。它实现了一个类路径扫描器,您可以在选择器中传递它。它像游客一样工作。这是我为你工作的,如果不是的话,从中得到一些想法。请参见末尾的示例注释选择器。

    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;
            }
        }
    }