2

想要执行以下操作:

引导程序 {
  def init = {servletContext ->
  ...........
  MyDomainClass.metaClass.save = {->
     委托.extraSave()
     //////// 如何在这里调用原始的 save()?
  }

}
…………
}

PS MyDomainClass#extraSave 定义为public void extraSave(){.....}

4

3 回答 3

4

首先,Bootstrap.groovy 可能不是进行这种元编程的最佳场所。这种方法的问题在于,对类的更改将在应用程序启动时应用,但在重新加载应用程序时您可能会丢失这些更改。显然,这只是开发过程中的一个问题,如果您不介意每次进行更改时都重新启动服务器,那么这根本不是问题,但我敢打赌这很快就会成为一个主要的烦恼。为了在重新加载应用程序时也应用更改,您应该将元编程移动到插件中,您可以在其中挂钩到onChange应用程序生命周期事件。

所以步骤是:

  • 创建插件
  • 在插件描述符的doWithDynamicMethods和闭包中进行元编程onChange

这是一个完整的示例,我在所有控制器类上“覆盖”了 chain() 方法。为域类的 save() 方法做同样的代码应该只需要一些明显的替换,例如使用application.domainClasses代替application.controllerClasses

def doWithDynamicMethods = {ctx ->

    application.controllerClasses.each {controller ->
        replaceChain(controller)
    }
}

def onChange = {event ->
    if (application.isArtefactOfType(ControllerArtefactHandler.TYPE, event.source)) {
        def clz = application.getControllerClass(event.source?.name)
        replaceChain(clz)
    }
}

private replaceChain(controllerClass) {

    // Save a  reference to the grails chain() method
    def grailsChain = controllerClass.metaClass.pickMethod("chain", [Map] as Class[])

    controllerClass.metaClass.chain = {Map params ->

        println "My code to execute before chain goes here"

        // Invoke the grails chain() method
        grailsChain.invoke(delegate, [params] as Object[])

        println "My code to execute after chain goes here"
    }
}
于 2009-11-03T15:12:44.620 回答
2

为什么不为此目的利用 GORM 事件呢?在域类中:

def extraSave() {
    // ...
}

def beforeInsert = {
    extraSave()
}

def beforeUpdate = {
    extraSave()
}

恕我直言,这是一种更清洁的方法。文档可以在这里找到

于 2009-11-03T15:41:14.347 回答
1

不确定以下是否有效,但这可能是一个解决方案:

MyDomainClass.metaClass.origSave = MyDomainClass.metaClass.save
MyDomainClass.metaClass.save = {-> 
   delegate.extraSave()
   delegate.origSave()
}

如果上述方法有效,请给我反馈...

于 2009-11-03T08:55:12.163 回答