I am experimenting with RequestFactory (RF) for the first time and am struggling to implement my first ServiceLocator
.
From the RequestContext
:
// Sign a user in or out of the app.
@ServiceName(
value="com.myapp.server.DefaultSignInOutService",
locator="com.myapp.server.DefaultSignInOutServiceLocator"
)
public interface SignInOutService extends RequestContext {
public Request<String> signIn(SignIn signIn);
public Request<Void> signOut(SignOut signOut);
}
And then the DefaultSignInOutServiceLocator
:
public class DefaultSignInOutServiceLocator implements ServiceLocator {
// I am using Guice-3.0 for server-side DI, and ServiceLocatorModule is an AbstractModule.
ServiceLocatorModule serviceLocatorModule = new ServiceLocatorModule();
// Will be initialized by Guice.
private DefaultSignInOutService signInOutService;
public DefaultSignInOutServiceLocator() {
super();
// Bootstrap DI.
Injector injector = GWT.createInjector(serviceLocatorModule);
// injector.getInstance() returns a fully-configured/wired
// DefaultSignInOutService instance.
setSignInOutService(injector.getInstance(SignInOutService.class));
}
@Override
public Object getInstance(Class<?> clazz) {
// I'm trying to use proper DI best practices here, and avoid code like:
//
// return new DefaultSignInOutService(true, "Yes", 35);
//
// Rather, I'd like to be able to return an already pre-configured service impl:
return signInOutService;
}
// Getters/setters, etc.
}
My understanding is that the ServiceLocator
s are basically factories for service implementations. If that's true, then if I'm using Guice for server-side DI, I need to initialize my Guice module from inside the locator's constructor. However, if there is any code that I need to write myself (elsewhere in the app) that creates an instance of DefaultSignInOutServiceLocator
and calls its getInstance()
method explicitly, then I don't need to put the ServiceLocatorModule
inside DefaultSignInOutServiceLocator
. In that case, I could have code like this:
public class DefaultSignInOutServiceLocator implements ServiceLocator {
@Injected
private DefaultSignInOutService signInOutService;
@Override
public Object getInstance(Class<?> clazz) {
return signInOutService;
}
// Getters/setters, etc.
}
So here are my questions:
- Are
ServiceLocator
impls an appropriate place to put Guice modules (and thus bootstrap DI from inside them)? Otherwise, how can I inject the locator with a properly-wired/confgured service impl? - Or, am I just not understanding the purpose of
ServiceLocator#getInstance()
? - And if I am on the right track here, then what "scope" (Spring DI terminology) should the injected
signInOutService
be? Should it be a singleton or a multiton/prototype? Do I need to worry about thread-safety here (multiple threads obtaining the samesignInOutService
instance)? Or does GWT somehow ensure that the RequestFactoryServlet accesses locators in a thread-safe way?
ServiceLocator
s are instantiated by aServiceLayerDecorator
, and you can plug your own.ServiceLocator
s and the service instances they create a almost singletons (they could be garbage-collected in case the available memory is low, and new instances recreated afterwards), so you should either configure them as singletons on your side or at least make sure you treat them as such (i.e. injectProvider
s for request-scoped values such as the current user).You can find a complete example in the form of a Maven archetype at https://github.com/tbroyer/gwt-maven-archetypes