Reputation: 61
I'm building a grails app and have come across an issue when trying to instatiate a service, in a different service. Both of the services use a method defined in the other eg.
class fooService{
def barService
barService.doIt()
def getIt(){
...
}
}
class barService{
def fooService
fooService.getIt()
def doIt(){
...
}
}
When I run the app and go to where the methods are used, it brings up this error;
Error creating bean with name 'fooService':
org.springframework.beans.factory.FactoryBeanNotInitializedException: FactoryBean is
not fully initialized yet
Is this something that cannot be done in grails? Or could anyone offer any advice?
Thanks
Upvotes: 5
Views: 5742
Reputation: 2459
You can handle the circular reference using the following -
Lets call it firstSerivce and secondService.
protected def firstService
def grailsApplication
def initialize() {
this.firstService = grailsApplication.mainContext.firstService
}
def secondService
def init = { servletContext ->
secondService.initialize()
...
..
Upvotes: 0
Reputation: 486
All these answers are excellent and show how to handle the problem through the framework. Although, when I had this problem I realized there must be a flaw in my plan and architecture if I absolutely must have services calling each other and causing conflicts. Instead of finding a work-around I took a slightly less complicated and strait forward approach -- I restructured. I moved the offending methods from the service class into another service class. It took some refactoring, rethinking and copy/paste skills but I think the application is better for it.
I'm not saying this is better than the other answers. I'm saying, this time, with this project refactoring was a better, faster, less complicated solution. I highly recommend it.
UPDATE Our final strategy is to refactor all "utility" service functions into a baseService class then have all other services that need the utility services extend baseService. The new policy is to avoid injecting services into other services, unless some situation arises that doesn't allow us to follow this inheritance pattern. This will give us a cleaner code base and less of a spaghetti trail of injections to follow. Plus, it eliminates the emergence of this error.
Upvotes: 2
Reputation: 31
Service can be called by another service but not possible at time of initialization. If you want to implement this, the way should be like.
class fooService{
def barService
def getIt(){
...
}
def anotherFooMethod(){
barService.doIt();
}
}
class barService{
def fooService
def doIt(){
...
}
def anotherBarMethod(){
fooService.getIt();
}
}
Upvotes: 3
Reputation: 122364
I've had similar issues in the past, but only when both services are transactional. If it's possible to make at least one of them non-transactional then it should work as-is. If that's not possible then the fallback is to do a kind of "late binding"
class FooService {
def grailsApplication
private getBarService() {
grailsApplication.mainContext.barService
}
public methodThatUsesBarService() {
barService.doSomething()
}
}
This will look up barService
in the app context at the point where it is used, rather than at the point where the FooService
is created.
Upvotes: 4
Reputation: 75671
That's not valid code, so it's hard to know what's really going on. Are the doIt()
and getIt()
calls in constructors? If so, change the services to implement org.springframework.beans.factory.InitializingBean
and do the calls in the afterPropertiesSet
method.
Upvotes: 1