【问题标题】:Groovy Extension Module Method - No Signature of MethodGroovy 扩展模块方法 - 没有方法签名
【发布时间】:2016-04-21 07:07:29
【问题描述】:

我在 java.util.ArrayList() 上创建了两个 groovy 扩展模块/方法。它在我的 IDE 中运行良好。我使用gradle 构建jar,并将其部署到远程JVM。当它到达远程JVM 时,它失败了。

这里是扩展方法:

    static Map sumSelectedAttributes(final List self, List attributes) {
    Map resultsMap = [:]
    attributes.each { attr ->
        resultsMap[attr] = self.inject(0) { sum, obj ->
            sum + obj[attr]
        }
    }
    return resultsMap

下面是调用它的代码:

outputMap[processName][iName] << kBeanList.sumSelectedAttributes([
    "messageCount", "userCount", "outstandingRequests",
    "cpuUsage", "memoryUsage", "threadCount", "cacheCount", "huserCount",
    "manualHuserCount", "dataPointerCount", "tableHandleCount",
    "jdbCacheRecordCount", "dbConnectionCount"])

这里是错误:

没有方法签名:java.util.ArrayList.sumSelectedAttributes() 是 适用于参数类型:(java.util.ArrayList) 值: [[messageCount,incomingConnectionsCount,outgoingConnectionsCount, ...]]

同样,它在带有测试用例的 intellij 中运行良好。远程 JVM 上有什么不同会阻止它工作?以下是我想到的一些事情:

  1. 远程 JVM 在我使用 2.4.5 时使用 Groovy 2.3
  2. 我们在远程 JVM 上使用自定义类加载器来加载类

除此之外,我找不到任何其他文档,说明我需要做些什么才能使扩展在远程 JVM 上工作。

非常感谢任何帮助。

根据评论,自定义类加载器似乎存在问题,这是处理一些类加载器操作的类。

class CustomLoader {
    static Map loaders = [:]
    static File loaderRoot = new File("../branches")

    static URLClassLoader getCustomLoader(String branchName) {
        if (!loaders[branchName]) {
            loaders[branchName] = new URLClassLoader(getUrls(branchName))
        } else {
            loaders[branchName]
        }
    }

    static URLClassLoader updateClassLoader(String branchName) {
        loaders[branchName] = null
        loaders[branchName] = new URLClassLoader(getUrls(branchName))
    }

    private static URL[] getUrls(String branchName) {
        def loaderDir = new File(loaderRoot, branchName)
        List<File> files = []
        loaderDir.eachFileRecurse{
            if (it.name.endsWith('.jar')) {
                files  << it
            }
        }
        List urls = files.sort{ it.name }.reverse().collect{it.toURI().toURL()}
        return urls
    }
}

【问题讨论】:

  • 当您说自定义类加载器时,它会敲响警报;) 通常,为了让 Groovy 能够加载扩展模块,该模块必须对 Groovy 运行时的加载器可见。这与您的应用程序正常工作的方式不同,因为应用程序类加载器需要查看运行时,但运行时看不到应用程序类。所以当然我现在想知道你在远程 JVM 上的实际类加载设置。
  • 感谢您的回复,听起来您已经立即发现了问题。在这种情况下,是不是根本不可能使用扩展模块。根据我的代码,您能推荐一些替代方法吗?我为此计划了很多代码。只是为了确认,为了后代,我刚刚在原始帖子中添加了“类加载器类”供您查看。它在一个开发盒上,我们需要同时加载不同版本的 jar,并且需要灵活加载更改而无需重新启动 JVM。 (开发/测试/产品分支)。

标签: java gradle groovy jar urlclassloader


【解决方案1】:

要手动注册扩展方法模块,您可以使用类似于 GrapeIvy 中使用的代码。因为葡萄有同样的问题,他们在错误的加载器中使一个 jar 可见,但仍想启用扩展方法。有问题的代码在这里:

JarFile jar = new JarFile(file)
def entry = jar.getEntry(ExtensionModuleScanner.MODULE_META_INF_FILE)
if (entry) {
  Properties props = new Properties()
  props.load(jar.getInputStream(entry))
  Map<CachedClass, List<MetaMethod>> metaMethods = new HashMap<CachedClass, List<MetaMethod>>()
  mcRegistry.registerExtensionModuleFromProperties(props, loader, metaMethods)
  // add old methods to the map
  metaMethods.each { CachedClass c, List<MetaMethod> methods ->
    // GROOVY-5543: if a module was loaded using grab, there are chances that subclasses
    // have their own ClassInfo, and we must change them as well!
    Set<CachedClass> classesToBeUpdated = [c]
    ClassInfo.onAllClassInfo { ClassInfo info ->
      if (c.theClass.isAssignableFrom(info.cachedClass.theClass)) {
        classesToBeUpdated << info.cachedClass
      }
    }
    classesToBeUpdated*.addNewMopMethods(methods)
  }
}

在这个代码文件中是一个代表 jar 的文件。在你的情况下,你需要在这里有别的东西。基本上我们首先将描述符文件加载到 Properties 中,调用 registerExtensionModuleFromProperties 根据给定的类加载器使用 MetaMethods 填充映射。这是解决问题的关键部分,这里正确的类加载器是一个可以加载扩展模块和 groovy 运行时中的所有类的类加载器!在此之后,任何新的元类都会知道扩展方法。仅当已经存在元类并且您想了解这些新方法时才需要下面的代码。

【讨论】:

  • 哇,我不相信会有解决方案。我非常感谢您的洞察力和信息!仅供参考,因为其他人的可支持性是一个相当大的因素,所以我决定将函数移动到一个 trait 会更简单,然后在我需要的任何地方实现它。总共花了 20 分钟... groovy 的强大功能和灵活性!
猜你喜欢
  • 2022-08-06
  • 2021-04-28
  • 2017-03-02
  • 2014-10-16
  • 2018-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多