7

I have a Grails application that needs to run a strategy that will likely be swapped out over time. I know Spring underlies Grails, so I was wondering if I had access to Spring's IoC container so that I could externalize the actual dependency in an xml file (note: I have never actually done this, but just know of it, so I may be missing something). My goal is to be able to do something like the following:

class SchemaUpdateService {
public int calculateSomething(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
IStrategy strat = (IStrategy) ctx.getBean("mystrat");
}
}

And then map the appropriate implementation in the beans.xml file. I assume this is supported in Grails. Does anyone have any documentation on how this would work? Do I really just need the Spring IoC library and it will just work? Thanks!

skaz
  • 21,962
  • 20
  • 69
  • 98

3 Answers3

5

You define your beans in resources.xml or resources.groovy. The grails documentation is very clear about how to access the Spring application context.

Dónal
  • 185,044
  • 174
  • 569
  • 824
hvgotcodes
  • 118,147
  • 33
  • 203
  • 236
  • Thanks so much. I think when I read through this the first time I didn't absorb any of it because I didn't have any context yet. Appreciate it! – skaz Sep 08 '11 at 15:16
  • @skaz, look at the FAQ at http://www.grails.org/FAQ , search for 'applicationContext' with your browser, it has some options too. – hvgotcodes Sep 08 '11 at 15:20
4

You can access the application context from any Grails artefact using

ApplicationContext ctx = grailsApplication.mainContext

You can then use this to retrieve whichever beans you're interested in:

IStrategy strat = (IStrategy) ctx.getBean("mystrat")

In classes that don't have access to grailsApplication, you could use a helper such as the following to access the application context and the beans therein

class SpringUtils {

    static getBean(String name) {
        applicationContext.getBean(name)
    }

    static <T> T getBean(String name, Class<T> requiredType) {
        applicationContext.getBean(name, requiredType)
    }

    static ApplicationContext getApplicationContext() {
        ApplicationHolder.application.mainContext
    }
}

However, this should only be necessary if you need to retrieve different implementations of the same bean at runtime. If the required bean is known at compile-time, just wire the beans together in resources.xml or resources.groovy

Dónal
  • 185,044
  • 174
  • 569
  • 824
4

First of all, you want to define your strategy in your grails-app/conf/spring/resources.groovy:

beans = {
    myStrat(com.yourcompany.StrategyImpl) {
       someProperty = someValue
    }
}

Then, you simply def the a property with the same name into your service:

class SomeGrailsService {
    def myStrat

    def someMethod() {
        return myStrat.doSomething()
    }
}

In any Grails artefact (such as services and domain classes), Grails will automatically give the myStrat property the correct value. But don't forget, in a unit test you'll have to give it a value manually as the auto-wiring does not happen in unit tests.

Outside of a Grails artefact, you can use something like:

def myStrat = ApplicationHolder.application.mainContext.myStrat

In Grails 2.0, Graeme et al are deprecating the use of the *Holder classes (such as ApplicationHolder and ConfigurationHolder), so I'm not quite sure what the Grails 2.0 approach would be...

Adam C
  • 585
  • 4
  • 14