Well, if I look at the spring documentation, it is like "Hey it can do a lot for you, but if you need decent transactional control, you need to bring your own JTA".
Spring is an application framework, not a system service provider. In the transaction area, it offers means for convenient transaction demarcation, both programmatic and declarative, with pluggable transaction management strategies. Declarative demarcation via AOP is possible on any POJO, without being tied to a specific backend strategy like JTA; that's an important (and to the best of my knowledge, unique) value proposition of Spring's transaction support.
For single-database transactions, Spring provides alternative strategies out-of-the-box, namely DataSourceTransactionManager (for a single JDBC DataSource), HibernateTransactionManager (for a single Hibernate SessionFactory) and JdoTransactionManager (for a single JDO PersistenceManagerFactory). All of them delegate to the local transaction management of the respective resource API, typically used with local resource factories. Note that those strategies also care for the lifecycle of transaction-scoped resources like Hibernate Sessions; this is something that the JTA API does not aim to cover in the first place.
If you need distributed transactions, i.e. transactions that span multiple transactional resources, choose the JtaTransactionManager strategy. It delegates to an available JTA subsystem: either the global one provided by your application server, or a local one like JOTM. Additionally, it also cares for transaction-scoped resources. Of course, you need to access corresponding transactional resources, typically fetched from the JNDI environment. You can also use this strategy for single-database transactions, but Spring's local transaction strategies offer compelling alternatives here.
So "decent transactional control" can be achieved with both local transaction strategies and JTA; the question is rather whether you actually need distributed transactions (what JTA was designed for). Note that the local strategies DataSourceTransactionManager and HibernateTransactionManager even support per-transaction isolation levels and the read-only mode of JDBC Connections, which isn't available with JTA because of its higher level of transaction abstraction.
And "not reinventing the wheel" sounds nice, but if a system depends heavily on third party libraries in any Java context, it will create maintenance hell in the short run if used in conjunction with - say - major application servers.
Spring does not aim to provide its own system service implementations; in that sense, we avoid reinventing the wheel. An important goal of Spring is to *avoid* unnecessary dependencies: If you don't need distributed transactions, don't depend on JTA; if you don't need global resources, don't depend on JNDI. And even if you do want to leverage the latter, keep the dependencies in your configuration rather than in your business object implementations.
For simple usage of Spring, all you need is spring.jar (or individual ones like spring-beans.jar plus spring-context.jar) and commons-logging.jar. If you want to use AOP, add aopalliance.jar; if you want to use CGLIB proxies, add cglib.jar; if you need neither, omit both. Dependencies are as minimal as possible, according to your usage level. Note that Spring is already used with all major J2EE application servers (both in development and in production); no noteworthy maintenance issues reported so far.
Also, the "IoC" programming model is in my experience nice and powerful - for good programmers. Unfortunately, most programmers are probably average or below average (by the very definition of "average") and for them this model is all but straightforward.
I disagree in that respect. Sure, inexperienced programmers tend to use (and like) ad-hoc solutions, but they're usually open to learning and adopting cleaner ways of application wiring. And once you've understood the basic idea, applying it is straightforward, particularly if you have sample apps and skeletons that illustrate simple scenarios. It typically become easier to work with than ad-hoc solutions quickly.
Juergen