Hibernate - Interceptors

Last Updated : 9 Apr, 2026

Hibernate Interceptor is an interface that allows developers to intercept and react to lifecycle events in Hibernate operations. It acts as a bridge between the Hibernate session and the application, enabling custom logic during database interactions.

  • Allows interception of operations like save, update, and delete
  • Provides callback methods to customize Hibernate behavior
  • Helps in implementing logging, auditing, and validation logic

Types of Interceptors

There are two ways of defining interceptors:

1. Implementing an Interceptor Interface

Implementing org.hibernate.Interceptor requires implementing about 14 accompanying methods. These methods include onLoad, onSave, onDelete, findDirty, and a few more. It is also important to ensure that any class that implements Interceptor interface is serializable (implements java.io.Serializable).

  • Requires implementing multiple methods like onLoad(), onSave(), onDelete(), etc.
  • Class must implement Serializable
Java
// Class 
public class CustomInterceptorImpl
implements Interceptor, Serializable {

    // Annotation 
    @Override 
    // Method 
    public boolean onLoad(Object entity, Serializable id, Object[] state,
                          String[] propertyNames, Type[] types) 
            throws CallbackException {
            
               // ... return false; }
               // ... @Override public String onPrepareStatement(String sql)
               {
                 // ... return sql; }
               }

If there are no special requirements, extending the EmptyInterceptor class and only overriding the required methods is highly recommended.

2. Extending EmptyInterceptor

Extending the org.hibernate.EmptyInterceptor class provides an easier way of defining an interceptor. We now only need to override the methods that relate to the operation we want to intercept.

  • Easier approach, override only required methods
  • No need to implement all methods

For example, we can define our CustomInterceptor as:

public class CustomInterceptor extends EmptyInterceptor { }

And if we need to intercept data saving operations before they are executed, we need to override onSave method:

Java
// Annotation 
@Override
// Method 
public boolean onSave(Object entity, Serializable id, Object[] state,
                      String[] propertyNames, Type[] types) {

    if (entity instanceof User) {

        logger.info(((User) entity).toString());
    }
    
    return super.onSave(entity, id, state, propertyNames, types);
}

This implementation prints the entity if it is a User. It’s recommended to call super.onSave() to allow event propagation. The onFlushDirty() method can be used to track changes and update fields like lastModified for auditing.

In the below method we will be illustrating how this can be achieved which is as follows:

Java
// Annotation
@Override
// Method
public boolean onFlushDirty(Object entity, Serializable id,
                            Object[] currentState, Object [] previousState,
                            String[] propertyNames, Type[] types) {
    if (entity instanceof User) {
        ((User) entity).setLastModified(new Date());
        logger.info(((User) entity).toString());
    }
    return super.onFlushDirty(entity, id, currentState, previousState, propertyNames, types);
}

Other events such as delete and load (object initialization) can be intercepted by implementing the corresponding onDelete and onLoad methods respectively.

Registering Interceptors

A Hibernate interceptor can either be registered as Session-scoped or SessionFactory-scoped.

1. Session-scoped Interceptor

A Session-scoped interceptor is linked to a specific session.

  • Applied to a specific session only
  • Registered while opening the session
  • Suitable for session-specific behavior

It's created when the session is being defined or opened as:

public static Session getSessionWithInterceptor(Interceptor interceptor)
throws IOException {
return getSessionFactory().withOptions() .interceptor(interceptor).openSession();
}

In the above, we explicitly registered an interceptor with a particular hibernate session.

2. SessionFactory-scoped Interceptor

A SessionFactory-scoped interceptor is registered before building a SessionFactory.

  • Applied to all sessions globally
  • Registered before building SessionFactory
  • Must be thread-safe

 This is typically done through the applyInterceptor method on a SessionFactoryBuilder instance:

ServiceRegistry serviceRegistry = configureServiceRegistry(); 
SessionFactory sessionFactory = getSessionFactoryBuilder(serviceRegistry).applyInterceptor(new CustomInterceptor()) .build();

A SessionFactory-scoped interceptor is applied to all sessions, so it should not store session-specific data since it is shared across multiple sessions concurrently.

  • For a session-specific behavior, it's recommended to explicitly open a session with a different interceptor as earlier shown.
  • For SessionFactory-scoped interceptors, we naturally need to ensure that it's thread-safe. This can be achieved by specifying a session context in the properties file:

hibernate.current_session_context_class=org.hibernate.context.internal.ThreadLocalSessionContext

Or by adding this to our XML configuration file:

<property name="hibernate.current_session_context_class"> 
org.hibernate.context.internal.ThreadLocalSessionContext 
</property>

Also, to ensure serializability, SessionFactory-scoped interceptors must implement the readResolve method of the Serializable interface.

Comment