1) Introduction
This article deals with Hibernate Interceptors. Hibernate is an open-source project that provides
ORM solution. For more information about Hibernate, novice readers are encouraged to read the article
An Introduction to Hibernate on javabeat before reading this article.
Situations may demand to perform some set of pre-requisite/post-requisite operations before/after the
core functional logic. In such a case, an interceptor can be used to intercept the
existing business functionality to provide extensible or add-on features. They provide pluggable
architecture and are generally callback methods that will be called by the framework in response to
a particular set of events/actions if properly registered and configured. They follow the standard Interceptor
pattern and they have various advantages in an application design. They can be used to monitor
the various parts of the input that are passed to an application to validate them. They even have the capability to overwrite
the core functional logic of the module.
For example, consider an online shopping system that ships goods to the customer's shipping address
upon placing a request. Suppose, there is an enhancement to this application telling that the
request has to be validated because of the increasing number of spams and the customer should be
notified through e-mail (or mobile) upon successful delivery of the goods. These two enhancements
have to be projected into the application's core logic.
Having a general overview of the core logic will look something like the following,
- Validate the User Request
- Ship the Goods to the customer
- Notify the customer about its successful delivery
As we can see above, the two enhancements have to be projected within the application's core
logic which requires code changes. But, if the application has to be properly designed with the
notion of Interceptors, then the code change can be eliminated to the maximum.
2) Interceptors in Hibernate
Hibernate provides an ORM solution for persisting and querying data in the database. A Hibernate
application can be structured in a way such that certain methods can be make to be invoked when
a particular life-cycle event occurs. Not always the API in a software/product will completely
satisfy the application needs and requirements. Hibernate is no more away from this. Therefore,
Hibernate API is designed in such a way to provide pluggable framework through the notion of
Interceptors.
In a multi-tiered application, the situation for the inclusion of Interceptors can happen at any
level. It can happen at the Client level, Server level and even at the persistence level. Imagine an
application is saving employee records in a database and now the application mandates to
display to the Database admin about the history of inserts and updates.
A simple general overview of the logic looks like the following,
- Insert/Update the records in the Database
- During Insert/Update, maintain the log information in a file
As we can see, the maintenance of this logging information should happen whenever when an
insert/update goes to the Database. Such a logger interceptor can be easily plugged into the
application with minimal code change because of the flexible design of Hibernate.
2.1) Types of Interceptors
Based on their scope, Interceptors in Hibernate can fall under two categories. They are,
- Application-scoped Interceptors
- Session-scoped Interceptors
2.1.1) Application-scoped Interceptor
An application can contain one or more database sessions represented by the
Session interface. If an
application is configured to use Global Interceptors, then it will affect the persistent objects in all
the sessions. The following code configures a global interceptor,
Configuration configuration = new Configuration();
configuration.setInterceptor(new MyInterceptor());
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session1 = sessionFactory.openSession();
Employee e1, e2 = null;
// Assume e1 and e2 objects are associated with session1.
Session session2 = sessionFactory.openSession();
User u1, u2 = null
//Assume u1 and u2 objects are associated with session1.
|
A global-scoped interceptor can be set to an application by calling the
Configuration.setInterceptor(Interceptor)
method.
In the above code, we have two different session objects
'session1' and 'session2'. Let us assume that e1 and e2
Employee objects are associated with session
'session1' and u1 and u2
User objects are associated with session 'session2'.
The applied application-scoped interceptor would have affected all the objects
(e1, e2, u1 and u2), even though they are in different sessions.
2.1.2) Session-scoped Interceptor
A session-scoped interceptor will affect all the persistent objects that are associated with that
particular session only. The following code shows how to configure a session-scoped interceptor,
Configuration configuration = new Configuration();
SessionFactory sessionFactory = configuration.buildSessionFactory();
MyInterceptor myInterceptor = new MyInterceptor();
Session session1 = sessionFactory.openSession(myInterceptor);
Employee e1, e2 = null;
// Assume e1 and e2 objects are associated with session 'session1'.
MyAnotherInterceptor myAnotherInterceptor = new MyAnotherInterceptor ();
Session session2 = sessionFactory.openSession(myAnotherInterceptor);
User u1, u2 = null;
// Assume u1 and u2 objects are associated with session 'session2'.
|
From the above code, we can infer that a session-scoped interceptor can be set by calling the method
SessionFactory.openSession(Interceptor).
In the above code, we have two different session objects 'session1' and 'session2'
being configured with interceptors MyInterceptor
and
MyAnotherInterceptor
respectively. So, e1 and e2 objects will be affected by
MyInterceptor, whereas u1 and u2 objects
will be affected by
MyAnotherInterceptor.
|