Loading...

Wednesday, March 6, 2013

Grails Goodness: Using Spring Bean Aliases

Grails uses dependency injection by convention. This means if we have a property messageService then a Spring bean or Grails service with the name messageService is injected. Grails will automatically use the name of a Grails service as the name of the Spring bean definition (applying Java Bean conventions and start with a lowercase). So if we have a Grails service MessageService the resulting Spring bean definition will have the name messageService. Any Spring bean that wants to use the service only has to create the property messageService and dependency injection by convention makes sure the Grails service is injected.

We can change the Spring bean definition name using Spring bean aliases. With an alias we provide an extra name for a Spring bean. In our Grails application we can add an alias in the grails-app/conf/spring/resources.groovy file. In the following sample we add the alias message for the MessageService Grails service:

// File: grails-app/conf/spring/resources.groovy
beans = {
    springConfig.addAlias 'message', 'messageService'
}

We can use aliases to provide different service implementations and conditionally (for example based on environment) activate an implementation. The class that wants to use the service only has to use the dependency injection by convention and define a property with a name. In the resources.groovy file we can then set the alias with the correct name to the implementation we need.

Let's see how this works with an example. Suppose we have a controller that depends on a service with the name messageService. We use an interface to define the type of the service in our sample, but that is not necessary, we could do the same thing without interfaces:

//File: grails-app/controllers/com/mrhaki/grails/spring/MessageController.groovy
package com.mrhaki.grails.spring

class MessageController {

    MessageService messageService

    def index() {
        render messageService.message
    }
}

Let's create the interface, which is very simple in our sample:

// File: src/groovy/com/mrhaki/grails/spring/MessageService.groovy
package com.mrhaki.grails.spring

interface MessageService {

    String getMessage()

}

Next we create two Grails services that implement the MessageService interface: MessageRemoteService and MessageLocalService:

// File: grails-app/services/com/mrhaki/grails/spring/MessageRemoteService.groovy
package com.mrhaki.grails.spring

class MessageRemoteService implements MessageService {

    String getMessage() {
        'Remote message'
    }

}
// File: grails-app/services/com/mrhaki/grails/spring/MessageLocalService.groovy
package com.mrhaki.grails.spring

class MessageLocalService implements MessageService {

    String getMessage() {
        'Local message'
    }

}

If we run the Grails application we don't have a Spring bean definition with the name messageService, but we do have two bean definitions with the names messageRemoteService and messageLocalService. To make sure the MessageController will have the correct service injected we need to add aliases to resources.groovy. By default we want to use the messageRemoteService as messageService, but during development we want to use messageLocalService:

// File: grails-app/conf/spring/resources.groovy
import grails.util.Environment

beans = {
    // Default we use the messageRemoteService as implementation of MessageService
    springConfig.addAlias 'messageService', 'messageRemoteService'

    Environment.executeForCurrentEnvironment {
        development {
            // In development we use messageLocalService as implementation
            // of MessageService.
            springConfig.addAlias 'messageService', 'messageLocalService'
        }
    }
}

So with aliases it is easy to swap service implementations, based on some condition. This can be very useful if we have a service and want to use a mocked or simplified version during development and test for example. This post is based on the presentation Under the hood: Using Spring in Grails and blog post by Burt Beckwith

Code written with Grails 2.2.1

3 comments:

Brian Kotek said...

Thanks as always! This is extremely cool.

Anonymous said...

Is there a way to access the request within the bean?


Bill

Hubert Klein Ikkink said...

@Bill: I don't know what you mean by accessing the request within the bean? The HttpRequest or something else?

Post a Comment