Browse DevX
Sign up for e-mail newsletters from DevX


Migrate Your J2EE Apps from EJB to Hibernate : Page 3

You've decided to switch from EJB to Hibernate for persistence in your J2EE applications, but you don't know what to do with your existing EJB tier. Learn how a few decisions upfront, some simple ground rules, and design patterns can smooth the transition.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

Hibernate Packaging and Configuration
To incorporate Hibernate into your application, you have several ways, including the following:
  • Import it as a self-contained project
  • Include it and other required Jars as utility jars in the EAR

Wherever you put Hibernate, you need to ensure that your application code can access Hibernate classes and that Hibernate can class-load application server transaction manager classes. It may need them to participate in container-controlled transactions. Additional infrastructure code created to assist Hibernate should be placed in a common package that logically belongs to the infrastructure tier, is able to access Hibernate, and is in turn visible to projects that use Hibernate.

The Hibernate Session Factory and Configuration classes are the main classes for bootstrapping Hibernate. You create a SessionFactory by first instantiating a Configuration instance, setting its properties, and then asking the Configuration instance to build a Session Factory. The SessionFactory is a relatively heavyweight object. You should ensure that you have only one factory instance per application (datasource or db-url,username) and that it is fully configured before you attempt to use it. Typically, the factory instance will be created when you first request a Hibernate session. A common pattern is to wrap up the initialization code and session management logic inside a HibernateUtil class. This class enforces that only one instance of the factory ever exists by using the Singleton (GoF) pattern or binding the factory into JNDI.

You can load and configure Hibernate object mappings in several ways, including:

  • Adding your object mappings into the main Hibernate-cfg.xml file. This has the advantage of being centralized, but it will not scale very well for a large project with many objects, projects, and developers competing for access to this one file. The file bloats very quickly.
  • Configuring object mappings in separate XML files, one per object, and adding mapping resource references to the Hibernate-cfg.xml file or registering mappings programmatically with the Hibernate Configuration class.
  • Registering mapped classes programmatically when the SessionFactory is created. In order to register your domain objects, your domain object classes must be visible to your HibernateUtil/initialization code. If your HibernateUtil class resides in an infrastructure project and your domain objects in a business project, then you'll have to make your infrastructure project depend on your business or move your Hibernate code into the business tier.

In terms of organizing your XML mapping files, the simplest and most common approach is to name them after the classes that they map and to place them in the same package as the class definition. The downside of this is that you may not want your persistence details inter-mingled with your domain objects, especially if they are being packaged up and served to a remote client tier. Alternatively, you can place your XML in a separate project or package that mirrors the domain object packaging namespace.

Session Handling Strategy
The Hibernate Session class is the main class for interacting with Hibernate. The session keeps track of your updates, services your queries, and performs flushing of updates to the DBMS. You need to carefully manage your session lifecycle and granularity to ensure that it is synchronized with your data access strategy. It should never be held open for longer than a single application transaction or accessed by multiple threads concurrently. Hibernate will tell you if you do!

The following are the three strategies for managing Hibernate sessions in the context of an application transaction:

  1. Session-per-request. The session spans a single client/server request reply—usually a single database transaction. The session is closed when the transaction concludes. This is the typical strategy in use by EJB J2EE architectures and is probably what you're already using.
  2. Session-per-request with detached objects. Objects are long-lived and span multiple client/server requests. Objects are detached and reattached to session instances.
  3. Long-lived session. A single session spans multiple client/server requests and is usually cached on the HTTPSession.

The current session is usually stored on a thread local variable inside the HibernateUtil class. This guarantees one session per thread and centralizes your session management logic. Rather than passing the session around as a parameter to all your methods, you can just access the HibernateUtil for the current active session whenever you need it.

The HibernateUtil manages the low-level mechanics of your session, but it doesn't imply anything about your chosen strategy. Session management logic that uses HibernateUtil must be placed in the client/server mediation tier to support your chosen strategy. This is the logic to control Session creation, flushing, and closing. This can be tricky to isolate and encapsulate, as your code must be placed into the top most level of your use-cases, the parts of your code that manage your transactions—typically your session beans.

If you use session management strategy 1 (session-per-request) then the template code to manage your sessions looks like this:

Try { // Initiate the current Session HibernateUtil.currentSession(); // Perform some CRUD operations // and execute some business logic // Ensure that all outstanding updates are flushed to the DBMS HibernateUtil.currentSession().flush(). }catch (SomeCheckedException e) { // Handle error // Rollback Container managed transaction } finally { // Close the Session at the conclusion of the request, regardless of // whether the transaction succeeded or failed HibernateUtil.currentSession.close(); }

You must add this code, or some variant of it, to every top-most session bean method in your application where requests enter and initiate transactions (i.e., methods marked as transactional) and perform CRUD requests using Hibernate. If you're using Session Façades (Sun BluePrints), this can become a daunting migration, as every façade method must be changed. If your façades are chained, for example, façade A invokes façade B, which invokes façade C and so on. You may then find that the Hibernate session gets flushed multiple times during an application transaction, which can lead to a lot of fine-grained DBMS I/O. One way to mitigate this is to make your HibernateUtil class smarter and perform an application-controlled flush only in the method that opened the session in the first place.

Alternative technologies such as AOP and Spring can deal with session management better than EJB, as the session management logic can be inserted transparently as a crosscutting concern. Spring provides a special interceptor to manage Hibernate sessions. However, standard J2EE has no way to intercept an EJB request and insert crosscutting code once it is inside the container. The only way to call inside a session bean is to leverage proprietary container interception APIs or build some level of indirection into the design (e.g., the EJB Command Pattern (Marinescu), J2EE COR pattern, or EJB-backed dynamic proxy). These client/server mediation patterns can make your life easier because they funnel requests via a single EJB stateless session bean. Your session management logic needs to be added in only one location.

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date