Archive for January 6th, 2009

Spring Bean Aliases in Grails

Tuesday, January 06th, 2009

I was looking at the source code of a Spring application recently and saw an applicationContext.xml element that I hadn’t seen before: <alias>. It turns out this has been around for quite a while, since v1.2 (2005). It sure would have been convenient several months ago.

My first Grails app was a Live Chat app for tech support. I used Comet, so I needed to access Grails beans from Java classes. I did this by having my Services implement an interface, and used that as the type for the Spring bean dependency injection.

But the problem with that was that in Grails you don’t get to choose the bean names of artifacts – there’s a strict convention, so a Service named ChatService is registered as chatService. But the convention I’ve always used is to name my interface ChatService and name the implementation class ChatServiceImpl. But then the Spring bean name would be chatServiceImpl.

In a regular Spring app I’d implicitly alias when I added the bean element to the applicationContext.xml file, e.g.

<bean id='chatService' class='' />

So instead I chose an option that I really dislike – I named the interface IChatService and the Grails Service ChatService.

But with the <alias> tag, I should be able to do what I want – name the interface ChatService and the Grails Service ChatServiceImpl, and add

<alias name='chatServiceImpl' alias='chatService' />

to resources.xml. The original bean name will still be there, but I can use the more natural bean name for dependency injection.

This doesn’t cause an error, but it doesn’t work either. I spent some time in a debugger and the alias is registered, but the application context that’s available when the app is running is different from the one that the alias was added to.

But it turns out that you can add programatically add aliases at any time, so I added the alias call to BootStrap.groovy:

class BootStrap {

  def grailsApplication

  def init = { servletContext ->
    grailsApplication.mainContext.registerAlias('chatServiceImpl', 'chatService')

  def destroy = {}

and now I can use the chatService alias as the bean name.

I noticed though that since aliases are stored in a Map and not directly in the bean registry, that ctx.getBeanDefinitionNames() only returns ‘real’ bean names and no aliases. But it turns out that it’s pretty simple to get all bean names and aliases:

def allNames = [] as Set
ctx.beanDefinitionNames.each { name ->
    allNames << name
    ctx.getAliases(name).each { alias -> allNames << alias }

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 License.