Custom event listener example in Grails documentat

2019-02-18 18:09发布

问题:

I'm trying to add a custom GORM event listener class in Bootstrap.groovy, as described in the Grails documentation but its not working for me. Here is the code straight from the docs:

def init = {
    application.mainContext.eventTriggeringInterceptor.datastores.each { k, datastore ->
        applicationContext.addApplicationListener new MyPersistenceListener(datastore)
    }
}

When I run it, the compiler complains that application and applicationContext are null. I've tried adding them as class level members but they don't get magically wired up service-style. The closest I've got so far is:

def grailsApplication
def init = { servletContext ->
    def applicationContext = servletContext.getAttribute(ApplicationAttributes.APPLICATION_CONTEXT)
    grailsApplication.mainContext.eventTriggeringInterceptor.datastores.each { k, datastore ->
        applicationContext.addApplicationListener new GormEventListener(datastore)
    }
}

But I still get errors: java.lang.NullPointerException: Cannot get property 'datastores' on null object.

Thanks for reading...

EDIT: version 2.2.1

回答1:

If you do:

ctx.getBeansOfType(Datastore).values().each { Datastore d ->
   ctx.addApplicationListener new MyPersistenceListener(d)
}

This should work without needing the Hibernate plugin installed



回答2:

That looks like it should work, although I'd do it a bit differently. BootStrap.groovy does support dependency injection, so you can inject the grailsApplication bean, but you can also inject eventTriggeringInterceptor directly:

class BootStrap {

   def grailsApplication
   def eventTriggeringInterceptor

   def init = { servletContext ->
      def ctx = grailsApplication.mainContext
      eventTriggeringInterceptor.datastores.values().each { datastore ->
         ctx.addApplicationListener new MyPersistenceListener(datastore)
      }
   }
}

Here I still inject grailsApplication but only because I need access to the ApplicationContext to register listeners. Here's my listener (simpler than what the docs claim the simplest implementation would be btw ;)

import org.grails.datastore.mapping.core.Datastore
import org.grails.datastore.mapping.engine.event.AbstractPersistenceEvent
import org.grails.datastore.mapping.engine.event.AbstractPersistenceEventListener

class MyPersistenceListener extends AbstractPersistenceEventListener {

   MyPersistenceListener(Datastore datastore) {
      super(datastore)
   }

   protected void onPersistenceEvent(AbstractPersistenceEvent event) {
      println "Event $event.eventType $event.entityObject"
   }

   boolean supportsEventType(Class eventType) { true }
}


回答3:

Finally stumbled onto a working Bootstrap.groovy, thanks to this post but I don't think its the best way to do it, rather its a work around.

def init = { servletContext ->
    def applicationContext = servletContext.getAttribute(ApplicationAttributes.APPLICATION_CONTEXT)
    applicationContext.addApplicationListener new GormEventListener(applicationContext.mongoDatastore)
}

So basically I'm hard-coding the MongoDB datastore directly as opposed to iterating over the available ones, as the docs suggest.

To save you reading the comments to the first answer, the adapted version I provided in the Question (as well as Burt's answer) only works if the Hibernate plugin is installed but in my case I was using the MongoDB plugin so had no need for the Hibernate plugin (it in fact broke my app in other ways).