简体   繁体   English

挂钩Grails域对象save()

[英]Hooking into Grails Domain object save()

I'm writing a grails plugin and I need to hook into the domain save() method to do some logic after the save. 我正在写一个grails插件,我需要挂钩到域save()方法,以便在保存后做一些逻辑。 I need to do this across multiple domain classes. 我需要在多个域类中执行此操作。 I'm trying to avoid hibernate events in the cases where a plugin user is not using hibernate with GORM. 我试图避免在插件用户没有使用带有GORM的hibernate的情况下的hibernate事件。

I've tried many thing but below is what I think should have had the best chance at working. 我尝试了很多东西,但下面是我认为应该有最好的工作机会。 In all cases grailsSave is null . 在所有情况下, grailsS​​ave都null How can I do this? 我怎样才能做到这一点?

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"
        //...
        }
    }
}

I have the following set in my *Plugin.groovy class: 我的* Plugin.groovy类中有以下设置:

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

I was unable to successfully get a reference to the save() methods during plugin/app initialization; 在插件/应用程序初始化期间,我无法成功获得对save()方法的引用; I don't know why. 我不知道为什么。 Instead, I decided to create a listener for the hibernate events after insert, update, and deletes. 相反,我决定在插入,更新和删除之后为hibernate事件创建一个监听器。 This post by Sean Hartsock regarding the Audit Logging plugin was a perfect primer for doing that. Sean Hartsock关于审计日志插件的这篇文章是这样做的完美入门。

Here's the gist of the 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
        }   
    }

Then in the *GrailsPlugin.groovy: 然后在* 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
}

Fairly simple at the end of the day... 在一天结束时相当简单......

There are three different version of save added to the metaClass, metaClass中添加了三种不同版本的save,

save(Map)
save(Boolean)
save()

Which one are you calling in your testing? 你在测试中打电话给哪一个? You'll need to add you code to each one. 您需要为每个代码添加代码。

Another thing to check is whether your plugin is running after the hibernate plugin which adds the three methods to the metaClass 要检查的另一件事是你的插件是否在hibernate插件之后运行,它将三种方法添加到metaClass

cheers 干杯

Lee 背风处

Have a look at the Falcone Util plugin. 看看Falcone Util插件。 This plugin allows you to hook into Hibernate events (see documentation at the bottom of the page). 这个插件允许您挂钩Hibernate事件(请参阅页面底部的文档)。 I don't know if this is exactly what you want, but you might get some hints. 我不知道这是不是你想要的,但你可能会得到一些提示。

Ps! 诗篇! I don't think the plugin works with Grails 1.2 yet. 我不认为该插件适用于Grails 1.2。

This is an issue of premature optimization: older versions of Groovy seriously penalized MetaClass mangling, and so GORM does not add all of its magic until it detects the need to. 这是一个过早优化的问题:旧版本的Groovy严重损害了MetaClass的修改,因此GORM在检测到需要之前不会添加所有的魔法。

Easiest solution is to have your plugin dependOn GORM Labs (I work around it there). 最简单的解决方案是让您的插件依赖于GORM实验室(我在那里解决)。 The alternative solution is to trigger methodMissing manually (which would be duplicating the work I did). 另一种解决方案是手动触发methodMissing(这将重复我所做的工作)。 See the GORM Labs documentation for details on how I accomplished that. 有关如何完成该操作的详细信息,请参阅GORM实验室文档。

Wouldn't this best be added to the service class that owns the unit of work? 这不是最好添加到拥有工作单元的服务类吗? That's where the usual Spring/Grails idiom would have such logic. 这就是通常的Spring / Grails成语具有这样的逻辑的地方。 You needn't modify the save at all. 您根本无需修改保存。

Additional GORM methods are lazily initialized on first call to any of them. 其他GORM方法在第一次调用它们时会被懒惰地初始化。 To initialize them in doWithDynamicMethods simply call one of the static methods on your domain class(es): 要在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[])
        //...
    }
}

Your save() method will be available now. 您的save()方法现在可用。 As this is called at start up a single count shouldn't be to much of a problem. 由于这是在启动时调用的,因此单个计数不应该是一个大问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM