7

我正在编写一个 grails 插件,我需要连接到域 save() 方法以在保存后执行一些逻辑。我需要跨多个域类执行此操作。在插件用户未将休眠与 GORM 一起使用的情况下,我试图避免休眠事件。

我已经尝试了很多事情,但以下是我认为应该有最好的工作机会。在所有情况下grailsS​​ave都是null。我怎样才能做到这一点?

def doWithDynamicMethods = { ctx ->
    application.domainClasses.each { dc ->
        def grailsSave = dc.metaClass.pickMethod('save', [Map] as Class[])

        domainClass.metaClass.save = { Map params ->
        grailsSave.invoke(delegate, [params] as Object[])
        println "Saved object, now do my thing"
        //...
        }
    }
}

我的 *Plugin.groovy 类中有以下设置:

def dependsOn = [domainClass: '1.1 > *', hibernate: '1.1 > *']
def loadAfter = ['hibernate']
4

6 回答 6

6

在插件/应用程序初始化期间,我无法成功获取对 save() 方法的引用;我不知道为什么。相反,我决定在插入、更新和删除之后为休眠事件创建一个侦听器。Sean Hartsock 的这篇关于 Audit Logging 插件的帖子是一个完美的入门指南

以下是 Listener 的要点:

class MyListener implements PostInsertEventListener, PostUpdateEventListener, PostDeleteEventListener, Initializable {

        public void onPostInsert(final PostInsertEvent event) {
            // logic after insert
            return
        }

        public void onPostUpdate(final PostUpdateEvent event) {
            // logic after update
            return
        }

        public void onPostDelete(final PostDeleteEvent event) {
            // logic after delete
            return
        }


        public void initialize(final Configuration config) {
            return
        }   
    }

然后在 *GrailsPlugin.groovy 中:

def doWithApplicationContext = { applicationContext ->

    // add the event listeners for reindexing on change
    def listeners = applicationContext.sessionFactory.eventListeners
    def listener = new MyListener()

    ['postInsert', 'postUpdate', 'postDelete'].each({
       addEventTypeListener(listeners, listener, it)
    })

}


// copied from http://hartsock.blogspot.com/2008/04/inside-hibernate-events-and-audit.html
private addEventTypeListener(listeners, listener, type) {
    def typeProperty = "${type}EventListeners"
    def typeListeners = listeners."${typeProperty}"

    def expandedTypeListeners = new Object[typeListeners.length + 1]
    System.arraycopy(typeListeners, 0, expandedTypeListeners, 0, typeListeners.length)
    expandedTypeListeners[-1] = listener

    listeners."${typeProperty}" = expandedTypeListeners
}

在一天结束时相当简单......

于 2009-12-27T00:00:53.640 回答
2

元类中添加了三个不同版本的保存,

save(Map)
save(Boolean)
save()

您在测试中调用的是哪一个?您需要为每个代码添加代码。

要检查的另一件事是您的插件是否在 hibernate 插件之后运行,它将三个方法添加到 metaClass

干杯

于 2009-12-24T03:21:33.193 回答
2

看看Falcone Util插件。该插件允许您连接到 Hibernate 事件(请参阅页面底部的文档)。我不知道这是否正是你想要的,但你可能会得到一些提示。

附!我不认为该插件适用于 Grails 1.2。

于 2009-12-25T16:53:25.723 回答
2

这是一个过早优化的问题:旧版本的 Groovy 严重惩罚了 MetaClass 重整,因此 GORM 在检测到需要之前不会添加所有魔力。

最简单的解决方案是让你的插件依赖 GORM Labs(我在那里解决它)。另一种解决方案是手动触发 methodMissing (这将重复我所做的工作)。请参阅 GORM Labs 文档以了解有关我如何完成此操作的详细信息。

于 2009-12-28T16:33:08.293 回答
1

这不是最好添加到拥有工作单元的服务类中吗?这就是通常的 Spring/Grails 习惯用法具有这种逻辑的地方。您根本不需要修改保存。

于 2009-12-24T01:30:49.597 回答
1

其他 GORM 方法在第一次调用它们中的任何一个时都会延迟初始化。要初始化它们,doWithDynamicMethods只需调用域类上的静态方法之一:

def doWithDynamicMethods = { ctx ->

    application.domainClasses.each { dc -> 

        // call any static method to initialize dynamic gorm methods
        dc.clazz.count()

        def grailsSave = dc.metaClass.pickMethod('save', [Map] as Class[])
        //...
    }
}

您的 save() 方法现在可用。由于这是在启动时调用的,因此单个计数应该不是什么大问题。

于 2010-08-04T20:16:18.287 回答