WebBeans simple injection tutorial
Rick Hightower has a great tutorial on DI on java.dzone.com. Since Hightower’s tutorial is written based on Spring’s DI, I thought it would make a good comparison to WebBeans (JSR-299), so you can see the similarities and differences.
In the example, I want to create and configure an ATM machine with a selected transport and make the ATM machine available to servlets, JSPs, and JSF. The example is an ATM machine with an ATMTransport. In this example prototype, we start with a single transport StandardATMTransport. Later, I’ll show how to select one transport out of several, like choosing a database driver.
Since we’re using WebBeans, I’m putting the classes in WEB-INF/classes, and the WebBeans control file will be in WEB-INF/classes/web-beans.xml.
The example client might be a servlet, and since servlets are WebBeans-aware, we can inject the configured ATM machine directly into our servlet. To select the configured ATM machine, I use @Current, a WebBeans @BindingType. A @BindingType is an application-meaningful annotation selecting one of many configured WebBeans. When the WebBeans service is unique, I can use @Current to select the unique configured instance.
package example;
import javax.webbeans.Current;
import javax.servlet.*;
public class MyServlet extends GenericServlet {
@Current
private ATMMachine _atm;
...
}
Since my servlet uses an ATMTransport, I’ll need to define the interface. In general, it’s a good idea to define and inject service interfaces rather than injecting the service implementation itself. Using an interface decouples your client code from the implementation, letting you swap out service implementations, e.g. for testing.
package example;
public interface AutomatedTellerMachine {
void deposit(BigDecimal bd);
void withdraw(BigDecimal bd);
}
My ATM implementation class needs an ATMTransport to connect with the bank. Because there’s only one ATMTransport active at a time, I can use @javax.webbeans.Current as the @BindingType.
package example;
import javax.webbeans.Current;
public class AutomatedTellerMachineImpl implements AutomatedTellerMachine{
@Current
private ATMTransport transport;
public void deposit(BigDecimal bd) {
...
transport.communicateWithBank(...);
}
}
I define the ATMTransport,
public interface ATMTransport {
void communicateWithBank(byte [] datapacket);
}
A single implementation, StandardATMTransport,
public class StandardATMTransport {
public void communicateWithBank(...) {
...
}
}
Now the XML configuration (oh no!) is the file WEB-INF/classes/web-beans.xml. If you package your application as a jar, the web-beans.xml belongs in the root directory of the jar containing the WebBeans. In our example, I can create an almost-empty file
<WebBeans xmlns="urn:java:javax.webbeans"> </WebBeans>
And I’m done. When Resin starts the web-app, it will start a WebBeans manager, which scans the classpath for web-beans.xml files. When WebBeans finds the web-beans.xml it parses the file, and scans all the classes for Simple Beans, i.e. my WebBeans. In our example, it will find AutomatedTellerMachineImpl and StandardATMTransport and automatically publish them into the WebBeans manager. When Resin starts MyServlet, it will inject the discovered AutomatedTellerMachine service.
Some important things to notice.
- The injection is type-safe. Since WebBeans is designed around typed injection, I can inject the unique ATM and ATMTransport based only on its type.
- Beans do not have names by default, even internally to the WebBeans manager. In this example,
the beans are registered purely by their types and by the @Current annotation. - The XML configuration can be trivial and almost non-existent.
- The implementation bean does not need WebBeans annotations. This is important so annotations don’t go crazy, and also so you can use libraries that were not designed for WebBeans.
- Injection uses typed @BindingType annotations to select beans. In this example, my beans are unique so we can use @Current. If I had several ATM or ATMTransport beans, I’d create application-meaningful @BindingType annotations to select the one I wanted.
- The namespace for the WebBeans element in the web-beans.xml is “urn:java:javax.webbeans”, i.e. the package of WebBeans itself. This will become important later when we configure beans in XML.
Conclusion
So far, I’ve just sketched a minimal working prototype of the example. In my next blog posting, I’ll complete Hightower’s example, by selecting one of several transports, and finally compare the style of my implementation to the original tutorial.
