Even during OSCON, I've been churning out code for Tapestry 5.
The new Tapestry IoC container is rapidly coming together. The idea of replacing XML with Java classes (and naming conventions and annotations) is working out wonderfully. I'm busy putting together a version of configurations about now.
What I'm finding, as I code and also predict how the final Tapestry code will use the container, is some steep improvements.
In Tapestry IoC, injection isn't into your beans via property setters or constructors, the way it is in HiveMind and Spring. Instead, injection is via parameters to your builder methods. Injection via method parameters will also occur into decorator methods (the replacement for service interceptor factories) and into contribution methods (which contribute values into service configurations).
For example, in Tapestry IoC:
package org.example.myapp.services;
import org.apache.tapestry.ioc.annotations.Id;
@Id("myapp")
public class MyAppModule
{
public Indexer buildIndexer()
{
return new IndexerImpl();
}
}
The above defines a service "myapp.Indexer" as an instance of IndexerImpl. The equivalent in
HiveMind would be :
<module id="myapp" version="1.0.0" package="org.example.myapp.services">
<service-point id="Indexer">
<create-instance class="IndexerImpl"/>
</service-point>
</module>
That's already an improvement. By the time you start talking about dependencies, things get even better:
public Indexer buildIndexer(String serviceId, Log serviceLog,
@InjectService("JobScheduler") JobScheduler scheduler,
@InjectService("FileSystem") FileSystem fileSystem)
{
IndexerImpl indexer = new IndexerImpl(serviceLog, fileSystem);
scheduler.scheduleDailyJob(serviceId, indexer);
return indexer;
}
What's worthy of note here is how dependencies get injected in (as method parameters), and that lifecycle concerns about the IndexerImpl are separate from
its implementation. We don't have to inject the scheduler into IndexerImpl in order for the Indexer to be scheduled by the scheduler ... that concern can be implemented only in the builder method.
To accomplish that kind of separation in either HiveMind or Spring would require quite a bit of hackery; say, creating a new, specialized kind of ServiceImplementationFactory (in HiveMind) that understood about talking to the scheduler. Lots of work for something that can be expressed so easily in a short, simple, testable Java method.
I think that we'll see this approach bear fruit in the form of fewer services to accomplish the same goals. It will allow for non-service objects to easily receive injected services ... such objects can be created "on the side" by builder methods (or contributor methods).
This is the theme for all of Tapestry 5: Simpler, easier, faster, more understandable, more powerful. Avoid XML. Improve productivity. Make the framework adapt to your classes and your methods, rather than the other way around.