Coldfusion CreateObject() 返回错误对象的实例

use*_*882 6 coldfusion cfc createobject coldfusion-2021

我遇到了一个似乎只影响我们的生产服务器的问题,没有任何明显的规律或原因。本质上,我们收到以下错误(我将使用虚拟名称来说明这一点):

消息:在组件 Components.services.SomeComponent 中找不到方法 someFunction,在任何实现接口中也没有任何具有此名称的默认方法。

这种情况发生在代码库中的几行不同的地方,但一旦被抛出,它就永远不会再超过该点,直到清除 CFADMIN 中的组件缓存。关键在于:代码中的违规行如下所示:

<cfset var a = createObject("Components.services.app.ComponentA").someFunction() >

似乎createObject对 create ComponentA 的调用返回的是SomeComponent的实例。我尝试过以下方法:

  • 本节中的 CreateObject 调用一直使用动态创建的字符串作为组件路径...我想也许有些东西被污染了,所以现在Components.services.app.ComponentAComponents.services.app.ComponentB等等...都是硬编码的
  • 我尝试使用new语法而不是createObject
  • 我认为组件缓存变得混乱的路径可能有问题,所以我创建了一个映射到./Components/services/app调用(例如)“app”,这样我就可以创建像这样的对象new app.ComponentA()而不是new Components.services.app.ComponentA

似乎没有什么帮助——这些在我们的 UAT 或任何人的开发环境中都无法重现,并且在生产中是间歇性的,但是,一旦抛出,服务器就完成了。清除 CFADMIN 中的组件缓存可以暂时修复它,直到几个小时后有人再次随机抛出它。

一些额外的警告:

  • 当我们移动和洗牌试图找到此问题的原因时,特定的行号和组件似乎发生了变化,但行为始终相同 -new ComponentC()是创建someComponent...new ComponentA()而不是创建someOtherComponent
  • 这种情况只发生在我们的代码库的一个特定部分,与我们的代码的其余部分相比,该部分使用了大量的对象继承。我们进行了彻底梳理,以确保不存在任何循环引用或类似内容,并且邪恶组件 ( someComponent, someOtherComponent) 是位于此目录之外的 CFC
  • 事实上,清除组件缓存似乎可以解决这个问题,这确实让我对组件缓存产生了怀疑……我只是对 CF 的了解不够,无法理解为什么缓存可能会返回与以下对象不同的对象的实例:它正在呼叫的那个

后续步骤(这些都不理想):

  • 完全禁用组件缓存,不想承受性能损失
  • 添加一些荒谬的代码,以便在抛出无效方法名称错误时以编程方式清除组件缓存

是否有某种方法可以精细地排除从组件缓存中检索某些 CFC,并在调用 createObject() 时强制重新评估它们?

小智 5

当组件使用具有应用程序映射的路径时,我以前见过这种行为。我在几种不同的场景中见过这种情况,但最常见的场景是这样的:

在您的 Application.cfc 中,有一个使用相对路径的组件映射。就像是:

this.mappings["/Components"] = expandPath("../some/relative/path/com");
Run Code Online (Sandbox Code Playgroud)

只要应用程序始终从与该应用程序相同的文件夹中初始化,那么Application.cfc就可以正常工作。但是,如果应用程序是从子文件夹初始化的,则Components映射不再指向预期的文件夹。

如果您需要使用相对路径进行映射,可以通过执行以下操作来避免这种情况:

variables.rootFolder = getDirectoryFromPath(getCurrentTemplatePath());
this.mappings["/Components"] = variables.rootFolder & "../some/relative/path/com";
Run Code Online (Sandbox Code Playgroud)

这应该强制映射始终使用相同的物理路径文件夹,即使是从子文件夹调用时也是如此。

我看到这种情况发生的另一种情况是在共享环境中,其中存在多个同名的应用程序。

如果您运行的网站的多个实例在您的 中使用相同的应用程序名称Application.cfc,则初始化的第一个网站最终会与其他应用程序共享其映射。如果应用程序不同,可能会导致找不到组件。

希望这两种情况之一能让您走上解决问题的正确轨道!