Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Grails Dependency Injection Outside of Services?

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!

like image 519
skaz Avatar asked Sep 08 '11 15:09

skaz


3 Answers

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

like image 139
hvgotcodes Avatar answered Nov 16 '22 02:11

hvgotcodes


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

like image 29
Dónal Avatar answered Nov 16 '22 04:11

Dónal


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...

like image 26
Adam C Avatar answered Nov 16 '22 03:11

Adam C