I've been doing a lot of work lately with the Spring Framework. I'm still a little undecided about dependency injection as a way to implement inversion of control. Certainly IoC is good in principle. Dependency injection can make for some pretty clean code. That's all well and good, but if that was all that Spring promised then there wouldn't be such buzz around it. The bigger thing that IoC in general and Spring in particular promise is to allow for more portable and reusable software components. This is The Holy Grail of software (or at least of object oriented programming.) However, simply declaring your dependencies and allowing your container to resolve those dependencies does not guarantee reusable software. Another pre-requisite is that all the dependencies resolve to things that are also reusable. For example, I could have controllers that declare a dependency to some BigBadService class. That class must have all of its dependencies declared, and they need to resolve to interfaces (or to some other class that in turn has its dependencies resolve to interfaces, etc.) So Spring could definitely be used to simply clean up some code, but it takes a lot more than just that to really reap benefits from Spring.
Enough about that, I wanted to talk about some of Spring's features. I really like it's implementation of dependency injection. I am among those people out there who gets annoyed with too many and overly complex XML configuration files. There are definitely frameworks that verge on having "xmlscript" as a secondary language. Spring is a little guilty of this. Their configuration files can get pretty ugly, but that usually indicates a very complex application. They can be pretty simple to start. For pure dependency injection, they are very simple and clean. It's when you start adding others things like transaction management and web flow that things get ugly. I definitely think that transaction management should be done through annotations, a la EJB 3.0. Configuring controllers is always somewhat complex. The legacy of the original servlet spec is going to push a lot of this complexity into ugly xml files, so I don't totally blame Spring for that.
Of course dependency injection is just one of the many features of Spring. I haven't tried them all yet, but I'll describe a couple. First, it's previously mentioned transaction management is pretty solid. I used the DAO+Hibernate modules for this. The one thing I didn't like was that it was a little tricky to declare transactions for a class that I did NOT want to Spring to manage the creation of. I had a class that I wanted created by a factory. Spring managed the creation of the factory. Since I had a factory, I did not need it to manage the creation of the objects created by that factory. However, I wanted those object to be transactional. So I had to have it manage the creation of those objects, though I was able to tell it to use the factory. I felt like I was jumping through a hoop here. Otherwise, the Hibernate integration was very easy and well done.
The other module I used was Spring MVC. When I read the documentation on this, it really seemed like a nice step forward from other MVC incarnations. Of course, I'm not actually a big fan of MVC. I think it encourages a lot of coupling between presentation and data. This is especially bad given that the motivation for MVC is a separation of these things. I worked on a project once where we had a nice architecture that involved session beans that exposed XML only. Our servlets then applied XSLT. The motivation was that we needed to expose the exact some business logic but to many different user interfaces. The big problem with this kind of architecture was that the XSLT became incredibly complex. That's where the biggest advantage of using an MVC framework comes from, at least to me. It handles data-binding (and related things like validation messages) nicely.
Back to Spring MVC... It is very easy to get started with, but also very easy to start having problems with. The reason is its flexibility. There are so many options, and many of them are designed to have you write less code. Whenever you write less code that means the container is doing more for you. The combination of lots of options + lots of "invisible" container services can cause a lot of confusion and unexpected behavior. Fortunately it didn't take me too long to sort through the different options and understand them well. The Javadocs were great for this, much better than any of the tutorials/quick-starts out there. Once you understand how each controller-type works, the associated options are obvious. I like the command objects in the framework. They encourage abstraction and less coupling between business objects and the UI. Of course it would be easy to abuse this and basically make your business objects the same as your command objects.
All in all, I'm very pleased with Spring. There are certainly many more features that I have not explored on it. Its web flow particularly interests me. I think its IoC implementation is nice, and both of its dao/transaction packages and MVC packages really help the developer to write less code while not burdening him with arduous configuration.