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