Our primary web application follows a standard 3-layer design: Presentation/UI layer, Services Layer, and Data Persistence Layer. We make use of CDI throughout our application, but without any other formal application frameworks. You won’t find any Spring in our site anywhere. A few years ago, Spring provided some real tangible benefits. With JavaEE’s recent changes and addition of CDI, there’s really no need to add so many dependencies into your application. Our Presentation/UI layer makes use of JSF 2.2, with some additional JavaScript mixed in here and there. Many people criticize the use of JSF, but we’ve found it to fit our needs rather well - once you know what you’re doing, that is. There are definitely some headaches getting started.
Our Service Layer makes use of both EJBs and POJOs. With recent changes to the JavaEE spec, there’s really little difference these days. EJBs have become much thinner in terms of memory usage and overhead. Most of our EJBs are Stateless, as we have little need for long-running states. We do make use of a few Message-Driven Beans (MDBs) that are used for asynchronous and event-based processing of data. E-mail notifications, for example, are pushed out using MDBs.
Our Persistence Layer is Hibernate/JPA. While ORMs are often discouraged and avoided, they are really no better or worse than any other technology. If you’re not familiar with SQL, don’t view ORMs as a way around this limitation. We make use of triggers, stored procedures (functions), SQL views, and native SQL queries throughout our application. There are times when pure JPA just doesn’t get the job done for you. One great CDI library we leverage in our Persistence Layer is [Apache Deltaspike](http://deltaspike.apache.org). One of our favorite components is the Data Repository module. This module makes it simple to create Repository pattern objects for use within your application. It’s a real timesaver.