Using Spring Events in Grails

17 / Jul / 2014 by madhav.khanna 8 comments

Hi all,

I have published a new blog post Using Spring Events in Grails.

Spring Events are basically used to perform events asynchronously.

In my use case I need to save hundreds of records in the database. So I use Spring Events to save records asynchronously.

There is a plugin available in Grails for using Spring Events which save us from XML configurations and also provides a publishEvent method which can be called from a domain class, a controller or a service in the application.

Plugin Link

Spring Events work around two classes

1. A class that extends ApplicationEvent
2. A class that implements ApplicationListener

and publishEvent method is used to raise event that will be listen by a listener.

Let’s start by taking an example.

Author

package com.demo.domain

class Author {

    String name
    Integer age
}

AuthorSaveEvent

package com.demo.events

import org.springframework.context.ApplicationEvent

class AuthorSaveEvent extends ApplicationEvent {

    AuthorSaveEvent(){
        super([])
    }

}

EventListnerService


package com.demo.service

import com.demo.domain.Author
 import com.demo.events.AuthorSaveEvent
 import grails.transaction.Transactional
 import org.springframework.context.ApplicationListener

@Transactional
 class EventListnerService implements ApplicationListener {

public void onApplicationEvent(AuthorSaveEvent event){
 (1..10000).each {
 new Author(name:"Madhav", age:23).save()
 }
 }
 }

UtilController


package com.demo.controllers

import com.demo.domain.Author
 import com.demo.events.AuthorSaveEvent

class UtilController {

def withSpringEvent() {
 AuthorSaveEvent authorSaveEvent = new AuthorSaveEvent()
 publishEvent(authorSaveEvent)
 render "Records saving has been Intailized"
 }

def withOutSpringEvent() {
 (1..10000).each {
 new Author(name: 'Madhav', age: 23).save()
 }
 render "All Records has been saved"
 }
 }

Let us talk about the flow of the application:

1. When we hit the action of a controller then it will raise an event using publishEvent method.
2. Then the event will be listened by onApplicationEvent method of a class which is implementing the ApplicationListener interface.
3. Now the block of code in onApplicationEvent method will be executed on a separate thread.

Comparsion of time taken for saving 10000 records

1. withOutSpringEvent – it will take 6 minutes 20 seconds approx
2. withSpringEvent – it will take 18 seconds approx

Hope this helps !!

– Madhav Khanna
madhav.khanna@intelligrape.com

FOUND THIS USEFUL? SHARE IT

comments (8)

  1. Fui Nusenu

    @Vivek, I totally agree with you on this. Running the same code withOutSpringEvent with a Thread.start() for each event is even much faster than implementing the spring event mechanism. I will say the only mistake in withSpringEvent code is that each save operation is not done asynchronously. Like @Roni says, that would have produced better results, or even 10 operations at a time, would have been better

    Reply
  2. Vivek

    I just did some bench marking using a sample application built along similar lines.

    The performance of DB persistence with/without events was quite comparable. (A difference of 1 second at max between the two.)

    I’d believe that the claims made in this post about the performance are false. :)

    Reply
  3. Vivek

    @Roni:

    I’d have agreed to that if we were generating 10 separate events that’d then run in 10(or whatever number) different threads. From what I see, we generate one event which is handled in the onApplicationEvent method (I’m sure it doesn’t spawn threads for any logic that’s inside the method.)

    This means that we still effectively have one thread that’s doing all the lifting. Please correct me if I’m missing something here.

    Reply
  4. Roni C. Thomas

    @Vivek This has more to do with how many concurrent writes are happening on the DB. Async processing will obviously improve performance timings since there would be lesser waiting time for the shared resource. In this case, there might be 10 records being written out by 10 threads rather than the 10 records being written out by a single thread.

    Given the fact that Hibernate creates a session if one does not exist, I’m inclined towards that conclusion until the pool does not get exhausted. Correct me if I’m wrong.

    Reply
  5. Vivek

    I’m not sure if using a background thread is going to improve persistence times as against while using a foreground thread. If yes, I’d be interested in knowing how that happens behind the scenes.

    Additionally, I’d also like to know the performance if it ran in the same thread inside a service method as opposed to a method inside a controller. By that, I mean calling authorService.populateDB() or some such from within the withoutSpringEvent action.

    Reply

Leave a comment -