Before finishing up, let's investigate a couple of common myths that haunt Guice. Some people who've seen the core Guice concepts, like you have now, are not entirely comfortable with them. It seems like a pretty good framework, but it still seems to leave a weird taste in the mouth. In my experience, the reason is often twofold. Take a look at the following statements:
- Annotations seem to be intrusive and introduce tight coupling.
- The Spring Framework has done what Guice does for years.
The first statement is simply not true. There's an interesting discussion on this on Bob Lee's blog that describes why. I'll summarize it for you here. Let's start off with Kevin Bourrillion's words on annotations: "They do absolutely nothing to impede you from testing your code, or from using the classes with Spring."
Bob Lee goes on to add that you can easily create a separate Guice integration package for your application if you don't want a compile-time dependency on Guice. Though SpringSource's Colin Sampaleanu argued that you'd still need the Guice JAR on your classpath when migrating to another framework because you're using Guice annotations in your code, in reality, this is a nonissue. Here's why:
- Annotations don't do anything; they're just metadata. Is JavaDoc intrusive if you mention Guice in it? As Kevin also points out in the blog post I quoted above, tight coupling would mean that "one cannot function without the other". Annotations do not introduce this kind of coupling.
- Technically speaking, you can get rid of the annotations in your application's compiled .class files. Just provide your own versions of the Guice annotations that don't have Retention.RUNTIME set.
Note: At this point, people often argue that Guice should make it possible for users to configure their own annotation, instead of @Inject. This appears to be a good idea, but it wouldn't buy you anything. Even if you were using your own annotations, you would still have them in your code, because you want to use Guice. I don't see how that's any different to using Guice's @Inject. On the other hand, that feature would enable Guice to make use of EJB 3's @Resource annotations, for example. That's a valid use case, there will be a more general way to enable this kind flexibility in a future Guice release.
I think the conclusion is simple. Some people hate it when JavaDoc pollutes their code; others don't. The annotations debate is, in my opinion, a matter of taste and nothing more. There is no solid technical argument against the use of annotations.
Let's move on to the second statement, which asserts that the Spring Framework has done what Guice does for years. That's true, as long as you're talking about the DI idiom in general. But there are some differences that you should be aware of.
First, the Spring Framework still heavily depends on XML configuration. Your configuration, containing object wiring as well as other properties, is externalized by default when using the framework. In more recent versions of the framework, notably version 2.5, Spring has added support for annotation-driven object wiring. Unfortunately, you will probably still end up defining your beans in XML. You can get away with a single line of XML if you really want to, but that mode of operation requires you to put your bean configuration directly on the beans themselves, which is not as flexible as, say, using Guice modules. Alternatively, you can also use the JavaConfig option, but that feels like writing XML in Java. Anyway, my advice is to stay away from Spring's annotation-driven configuration options altogether. If you're going to use Spring, use the XML. It's the best documented option, and tools like Spring IDE are good enough to compensate for a lot of the annoyances.
With Guice your configuration will be done in Java by default, with externalized properties as an option. Externalized object wiring configuration is highly overrated and often not worth the added complexity and tooling dependencies. When was the last time you really changed your object wiring after deployment?
Note: I should mention that you can and probably should solve your Guice dynamic object wiring needs, if any, by loading modules dynamically and not by fully externalizing configuration in a custom file format or scripting language (like Ruby).
Second, because Guice uses Java as its primary configuration option, its modules also get some things for free:
- There's no need to use tooling other than a Java IDE.
- Java's type safety means that the compiler catches a lot of your mistakes early.
- You get Java's documentation standard, JavaDoc.
- You also get Java's test frameworks, like JUnit.
As Bob Lee likes to put it, types are the natural currency of Java since version 5 of the platform.
Third, Guice is much smaller, is easier to learn and use, and has a much better power to complexity ratio than Spring. For an example of Guice's simplicity, I urge you to take a look at Guice AOP. The Spring Framework, however, definitely has its value, including full-featured integration with lots of open source and commercial products and various Java Enterprise Edition (Java EE) standards. I've used Spring in the past and will probably continue to use it. Guice is not the new Spring and doesn't try to be. In fact, there's no reason why both can't coexist.
Last but not least, let me emphasize that Guice is a DI framework, not a fullstack application framework like Spring. Comparing them in terms of feature set is like comparing apples and oranges. Use the frameworks that fit your needs.
Now that you have most of the basic building blocks, you're ready to stop eating fortune cookies and dive into the advanced functionality. Let me recap what you've seen so far. To use Guice, besides using a DI style of programming, you generally do the following:
- Tag your classes with @Inject and an optional binding annotation wherever you want Guice to provide a dependency for you.
- Tell Guice which implementation you want as a dependency. If it's not an implicit binding (a concrete class or through annotation configuration), specify those bindings in an implementation of Module.
- Make sure that your bindings are scoped correctly. Scopes define the binding's instances lifetimes.
- Create the Injector with the modules you've created, and get an instance of any class Guice knows about.
You also learned that:
- Annotations are not evil.
- Both the Spring and Guice frameworks have their strengths.
And remember: Every binding is represented by a Key, the whole Key, and nothing but the Key, so help me Bob.