xwork classFinder在jboss 7环境不能正确处理url resource的问题以及解决方法

在struts2中,有一个组件为classFinder,它可以在整个项目中查找任意一个指定条件的类。如查找实现了某一个接口的所有实现类,或者查找有指定注解的所有类。这个组件的好处自不用说,但是在jboss7环境下,即会出现查找不到对象的问题。

如以下的条件就不能查找任何信息:只查找以com.iflym包名开头的满足指定条件的类。那么,这个classFinder的构建方法就是:

    public ClassFinder(ClassLoaderInterface classLoader, String... dirNames) {
        this(classLoader, getURLs(classLoader, dirNames));
    }

这个方法,会按照指定的包名,组装多个url地址,那么在jboss7中,就会组装成以下的一个地址:

jboss/standalone/tmp/vfs/deplymentxxx/iflym.jar-xxx/contents/com/iflym

那么,在这个目录下,肯定没有任何东西。那么xword在实现jboss vfs的查找时,会使用以下方法进行定位:

            if (s.startsWith("class org.jboss.vfs.VirtualFile")) { // JBoss 7 and probably JBoss 6
                File physicalFile = readJBossPhysicalFile(content);
                return physicalFile.toURI().toURL();

    private static File readJBossPhysicalFile(Object content) throws Exception {
        Method method = content.getClass().getDeclaredMethod("getPhysicalFile");
        return (File) method.invoke(content);
    }

这样就会返回以上的文件目录的一个url对象,而实现上,这个url对象下面没有任何class文件,自然就不会返回任何信息。
以上的问题,只存在于我们要查找的类在一个jar中的情况,如果在classes目录下,是没有问题的。

解决这个问题,我们需要使用另一个组件:reflections。官方地下:http://code.google.com/p/reflections/

我们来看这个组件是如何处理这个问题的呢。它主要是在定位jar文件上作处理,而不是采用一次性处理。

1    定位jar文件

首先,reflections寻找满足条件的所有url,然后对信息进行过滤,如下面代码所示:

final URL url = urls.nextElement();
                    int index = url.toExternalForm().lastIndexOf(resourceName);//第1步
                    if (index != -1) {
                        result.add(new URL(url.toExternalForm().substring(0, index)));//第2步
                    } else {
                        result.add(url); //whatever
                    }

在第一步获得的url.toExternalForm()的数据为:

vfs:/E:/flym/server/jboss-as-7.1.1.Final/bin/content/xxx.war/WEB-INF/lib/iflym.jar/com/iflym/

而在第二步之后就变为:

vfs:/E:/flym/server/jboss-as-7.1.1.Final/bin/content/xxx.war/WEB-INF/lib/iflym.jar/

然后,进一步处理时,reflections会采用自实现的jboss_vfs(在Vfs类定义)来定义这个jar文件,实现如下所示:

                    Object content = url.openConnection().getContent();
                    Class<?> VirtualFile = ClasspathHelper.contextClassLoader().loadClass("org.jboss.vfs.VirtualFile");
//此处返回的physicalFile如 \tmp\vfs\deployment800d6f6036085323\iflym.jar-2004c0237b2b5279\contents
                    java.io.File physicalFile = (java.io.File) VirtualFile.getMethod("getPhysicalFile").invoke(content);
//此处返回的name为 ifym.jar
                    String name = (String) VirtualFile.getMethod("getName").invoke(content);
//此处为重点,即file为iflym.jar-2004c0237b2b5279/iflym.jar文件,
                    java.io.File file = new java.io.File(physicalFile.getParentFile(), name);
                    if (!file.exists() || !file.canRead()) file = physicalFile;

重点在于最后倒数第2句,即返回一个末尾为iflym.jar结尾的文件,而在jboss7上面,确定有这么一个文件,它的完整路径即为
E:\flym\server\jboss-as-7.1.1.Final\standalone\tmp\vfs\deployment800d6f6036085323\iflym.jar-2004c0237b2b5279/iflym.jar
这样,就最终查找到我们所需要的jar文件。

2    过滤java类

与sturts2不同,reflections是将满足条件的jar经返回回来,但这些jar包,可能就存在不满足包路径条件的类,这些类,是通过使用过滤器来完成的。在我们的使用包名过滤时,reflections会产生一个include的filter。那么当进行scan的时候,针对所有jar中的所有类,均会使用该过滤器进行处理,如果不满足条件,则会被丢弃,这也满足了我们只查找指定包下的类的要求。相应的代码如下:

//构造函数
if (param instanceof String) {
 builder.addUrls(ClasspathHelper.forPackage((String) param, classLoaders));
 filter.include(prefix((String) param)); 
}

//scan时 Refelections.scan
for (final Vfs.File file : Vfs.fromURL(url).getFiles()) {
    String input = file.getRelativePath().replace('/', '.');
    if (configuration.acceptsInput(input)) {

总结如下,sturts2(xwork)在处理类的思路和refelections的思路不一样,xwork想达到一步到位的效果,而reflections则根据实际的问题进行了拆分化处理,这样在处理不同的问题时,也能够根据具体的问题简单地进行处理,这也是代码重构的一种目的。而xwork从2.1版本到现在的2.3.x版本,相应的问题都没有处理,一部分原因也是该问题处理难度和复杂度的处理。

转载请标明出处:i flym
本文地址:https://www.iflym.com/index.php/code/201305130002.html

相关文章:

作者: flym

I am flym,the master of the site:)

发表评论

邮箱地址不会被公开。 必填项已用*标注