Evan,
Glad to know you're seeing some successes. Hope that is an ongoing trend.
As far as a web of robot legs, often it might seem worse than it is, given a
few mitigating factors:
1) if you're building a web app, then typically you will be able to make use
of request scoped values, given that often the object graph with which you
want to process a request is dependent on the type of request received.
As a contrived example, imagine if you had a sharded database of users.
Also imagine that the user for which you were processing a request was
easily identified from its URL (such as "
www.yourapp.com/process-user?user-id=123"). In this example, you want to
determine which database to use for each request, given each user might map
to a different physical database. You could add a Filter to perform the
work of mapping user-id => shard, and then you could seed the calculated
value into RequestScope.
This means that your robot legs problem is effectively solved by scoping,
given you could change your "static" PrivateModule bindings to use a scoped
value. For example, you might now have:
public class DatabaseConnectionSupplier {
private final Provider<String> databaseNameProvider;
// always be keeping your ctr's package private!
@Inject DatabaseConnection(
Named("database_name") Provider<String> databaseNameProvider) {
this.databaseNamedProvider = databaseNameProvider;
}
public DatbaseConnection supplyDatabaseConnection() {
// we know we're in scope now, so we can call .get()
String databaseName = databaseNameProvider.get();
.....
}
}
Of course this would be horrible inefficient, but it illustrates the scoping
point, I hope. Practically, you'd probably have a singleton pool and simply
dispatch from Map<String, DatabaseConnection>.
I've added an example on the Guice wiki that shows how to do this with a
Filter:
http://code.google.com/p/google-guice/wiki/ServletModule
2) MapBinder
MapBinder is powerful! It boils down to having a Map that can be populated
in a plugin-style fashion. In the context of this thread, it allows you to
have multiple object graphs pre-constructed, keyed off a value that you
would know at the time you need to decide which leg to use.
In the example above, a class that needs a DatabaseConnection might itself
be injected with:
Map<String, DatabaseConnection> connectionsByName;
Here, each DatabaseConnection would have the relevant name injected into it
upon construction (ala the PrivateModule solution). The DatabaseClient
class could then learn which DatabaseConnection it should use at runtime,
such as:
public class DatabaseClient {
@Inject DatabaseClient(Map<String, DatabaseConnection> cnxsByName) { ...}
public doSomethingRequiringTheDatabase(Integer userId) {
String databaseOfUser = shardingService.getShardForUser(userId);
DatabaseConnection databaseConnection =
cnxsByName.get(databaseOfUser);
.....
}
}
The difference here is ultimately a design question: whether to hide the
configuration behind a scope or to have it explicit within blogic is the
choice to make. A good rule of thumb to use is this:
if a value is required in several packages, or at least across several
classes, then scoping is often the best idea. otherwise, passing a value
directly is probably going to be more straightforward, and therefore the
better choice.
In other words, use scope judiciously, as, end of the day, it really is a
glorified global variable (but not in the pejorative sense), and this can
make it confusing to see where a scoped value "comes from."
* * *
To answer your other question, ServletModule goes well with GWT, mainly
because the two are somewhat independent. You'll want to use Google-Gin for
your client side injections, as it deals with the issues of GWT that drive
us all subtly mad (i.e., those issues requiring the java to be compilable to
js).
On the server side you can easily configure your resource servlets and
remote logging servlets with ServletModule, and I absolutely recommend you
do that!
The ServletListener, btw, is used only to bootstrap the app within a servlet
container. If you're not running within a container, such as using an
"embedded" servlet engine, you can do something programmatic, such as
this<http://code.google.com/p/penumbrous/source/browse/trunk/src/java/com/penumbrous/posts/p20110109/EmbeddedJettyExample.java>.
Either way, certainly it is advantageous to use ServletModule.
-Fred
On Mon, Jan 31, 2011 at 5:57 PM, Evan Ruff <[email protected]> wrote:
> Hey Fred,
>
> Thanks a lot for helping me get started with Guice. I believe I've gotten
> my DataSource injection stuff worked out. As you suggested, I created a
> PrivateModule that accepted an annotation and a properties filename in the
> constructor. I then instantiate this PrivateModule for however
> many separate DB connections I need, using the Singleton scope to facilitate
> connection pooling in the DB itself. The connections are injected into the
> various DAO's using the annotation for their respective data sources. I've
> converted over all my DAO Unit Tests and this seems to be work very well!
>
> After reading some more documentation and getting into the question of
> deployment and setup in an actual system, I have quickly encountered the
> "robot legs" scenario that you are describing above. If I used Guice to push
> as far into my code base as possible, I can see it deteriorating into a
> really messy web. Most of my applications are web-based running in a
> container. Is it smart to create a static injector instance in the
> application container's bootstrap (servlet listener or whatever) and then
> use that to instantiate the objects throughout the application's base nodes
> (say, in the servlet itself, or wherever)
>
> Is there a different or better approach to configuring the bindings for the
> application in a web context? I see a guice-servlet library in the 3.0 RC2
> which looks like it uses a Servlet Listener. Wondering how that jibes with
> GWT?
>
> Thanks for any help!
>
> E
>
> --
> You received this message because you are subscribed to the Google Groups
> "google-guice" group.
> To post to this group, send email to [email protected].
> To unsubscribe from this group, send email to
> [email protected]<google-guice%[email protected]>
> .
> For more options, visit this group at
> http://groups.google.com/group/google-guice?hl=en.
>
--
You received this message because you are subscribed to the Google Groups
"google-guice" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/google-guice?hl=en.