The good thing about java web frameworks is that there are so many of them. The bad thing about java web frameworks is that...well, there are so many of them!
Which stack to use depends on the nature of the application and its requirements in each tier.
Note that the choices you've given are in fact a superset and its subset.
Tomcat's focus is the web tier standards and technologies of JavaEE - namely,
servlets, JSP, and JSF - and some support for web tier clustering, authentication and database access.
Struts is not a JavaEE standard API, but very much based on the servlet and typically uses JSP as the view technology.
And Hibernate is a provider of the JPA persistence standard, one of the JavaEE standards.
JBoss and Geronimo JavaEE app servers both use Tomcat as their servlet container. And even Glassfish uses a derivative of Tomcat as its servlet container.
So whatever you choose, you're always choosing a subset of JavaEE. The question is which subset does the application need? For that, review each tier...
Web (presentation) tier:
The major categories here are
1) Page oriented frameworks: like Struts 1.x / 2.x, and Spring MVC
and
2) Component oriented frameworks: like JSF, Wicket, Vaadin, GWT
I usually choose based on how I want the user experience and user interface to be.
If I want something of a rich desktop-like experience with lots of in-page UI manipulation using ajax, I go for component oriented frameworks. They provide rich UI widgets, are cross-browser tested and have the class scaffolding necessary for getting data, handle pagination, etc. JSF is even event driven, giving it a Swing feel to it.
All this is possible even with the page oriented frameworks, but then you have to code all the javascript from scratch and you have to do the hard work of combining dumb HTML elements and their related javascript / ajax manipulation into cohesive UI "components". Even when using tested javascript frameworks like jQuery and jQuery UI, this can be time consuming (or atleast I've found it to be so...YMMV). So, I use page oriented frameworks only if the UI does not involve complex widgets and lot of in-page UI manipulation. When it doesn't, using page oriented frameworks is much much more pleasant compared to component oriented ones.
That said, if you're *learning* these, then learn both JSF and Struts/SpringMVC+JSP. You're sure to use one or both sometime or other.
Application / Business tier:
- Does your application logic require convenient horizontal scaling (which usually implies distributed application logic)? Do you anticipate so many users that you want to provision new nodes in a cluster quickly and conveniently?
- Does your application involve business logic workflows and business logic transactions (I don't mean just DB transactions...should the results of some business logic itself be rolled back?)?
- Does it require asynchronous batch processing or staged processing, using a messaging service?
- Does it require finegrained authorizations per use case, or is an entry level authentication enough?
- Does it involve multiple distributed databases or distributed database transactions?
If answer to one or more of these is a yes (especially the first one), then a full fledged, tested and tuned, battle ready JavaEE app server like Jboss or Glassfish is preferred.
It is possible to integrate one or more of these with Tomcat, and it may even work functionally, but then you can't be sure whether it'll fulfil all performance and security requirements till you have thoroughly tested it yourself.
If horizontal scalability is a must, then you probably should choose some "cloud" solution, because provisioning new nodes is easy and automated on demand, unlike regular hosting accounts where provisioning has to be done by your provider.
If your application logic is somewhat complex ("somewhat" is a subjective opinion here), then JavaEE6 has a reduced profile called the "Web profile". In web profile, you get all the web tier technologies, plus you also get a lightweight
EJB standard, transactions and JPA - but not JMS, authorizations, etc. Both JBoss and Glassfish provide a Web Profile version.
If these are not necessary now, but you anticipate some of them, then Tomcat should be ok but ensure that the hosting account provides the freedom to install new components (that means prefer a VPS or dedicated server, and not a shared JVM).
You can deploy the business logic as simple POJOs in Tomcat itself.
In all these configurations, you have the option of using Spring framework. Now, Spring provides both *design* scaffolding, and it also provides *implementation* conveniences. So using Spring as a default glue makes sense to me, to keep the design flexible, as well as help write less code using its convenience helpers.
As for CDI, I confess I haven't found a good use for it. It's a convenience to reduce lines of code and keep design flexible, but when already using Spring, I have no idea how it helps. I think it's mainly used when you're not using Spring at all.
Data tier:
The JavaEE6 app servers provide JPA already (JBoss uses Hibernate, but Glassfish uses Toplink - that should not matter as long as only JPA interfaces and annotations are used).
If using Tomcat, you can deploy Hibernate as a JPA provider, but stick to the JPA interfaces, so that migration is easy in future.