How to perform event handling in Spring / Listening for Custom Events in Spring

Any event handling mechanism involves the following components :

  1. An Event itself.
  2. A listener which performs action when the event occurs.
  3. An activity which is responsible for event generation such as a mouse click, record added, deleted and so on.
  4. A helper object (optional) involved in event chain.

A typical example of an event is a user changing his password. When a user changes his password, an e-mail is sent to his registered e-mail id informing of the password change. This scenario involves password changing logic and e-mail sending logic which, in a well designed application obviously, will be written in different places.

It is also possible that the application sends e-mail for various other events as well. Thus the presence of event handling mechanism is a necessary requirement. In its absence, calling a logic written at one place (e-mail sending logic for example) from multiple places becomes a tedious task and creates a tight coupling between code fragments.

Luckily, Spring supports an event handling mechanism where all the event modules (event, listener, publisher etc.) are all written as separate components and thus are loosely coupled making the development and maintenance of application much easier.

[sc name=”AD3″ ]

Spring’s Event Handler Framework

Relating to the components of event handling given at the start of this post, Spring’s event handler model consists of :

  1. An Event. An event in Spring is a class which  extends org.springframework.context.ApplicationEvent class (A User in above case).
  2. A listener class. A listener class in Spring is identified as a class which implements org.springframework.context.ApplicationListener. This class contains the action to be performed after the event occurs such as sending e-mail after the password is changed in our case.
  3. An activity. Which generates an event (changing password in above case). Activity is enclosed in a class which implements org.springframework.context.ApplicationListener interface.

Based on the above explanation, let’s look at the code implementing event handling in Spring. As before, the code is divided into components used in event handling flow.

The Event

 public class PasswordChangeEvent extends ApplicationEvent {
   String eventName;
   public String getEvent() {
      return eventName;
   }
   public void setEvent(String event) {
      this.eventName = event;
   }
   public PasswordChangeEvent(Object source, String eventType) {
      super(source);
      eventName = eventType;
   }
 }

First step in an event flow is the event itself. This is a Spring event as it extends ApplicationEvent class. When a class extends ApplicationEvent, it is forced to provide a constructor as ApplicationEvent lacks a no-arg constructor.

[sc name=”Leaderboard-ad” ]

The Listener Class

  public class PasswordChangeEventListener implements
      ApplicationListener<PasswordChangeEvent> {
     @Override
     public void onApplicationEvent(PasswordChangeEvent event) {
         System.out.println(event.getEvent() + " at " + event.getTimestamp());
     }
  }

Listener class is marked by implementing org.springframework.context.ApplicationListener interface. This interface accepts generic argument denoting the event type for which it listens so that it is invoked for matching events only. The event may be a framework event such as context initialized or any custom event such as Password Change event, as in this case. The ONLY condition is that it will extend org.springframework.context.ApplicationEvent.

org.springframework.context.ApplicationListener interface has just one method onApplicationEvent() which accepts the event for which it listens. Any class implementing this interface must also implement this method.
Listener class must be registered as a bean in Spring Application Context. For XML based configuration, it must be declared as a bean in configuration file as :

<bean id="passwordChangeEventListener" class="com.codippa.spring.PasswordChangeEventListener">

or for Annotation based configuration, annotate it with @Component annotation.

[sc name=”AD1″ ]

The Activity

 public class UserOperations implements ApplicationEventPublisherAware {
       /**
       * Framework's object 
       */
	ApplicationEventPublisher eventPublisher;
        /**
        *  Activity which will generate an event 
        */
	public void changePassword() {
		eventPublisher.publishEvent(new PasswordChangeEvent(this, "Password Changed"));
	}
 
	@Override
	public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
		eventPublisher = applicationEventPublisher;
	}
}

This is the class where the event for which we want to take an action resides. This class MUST implement org.springframework.context.ApplicationEventPublisherAware interface and thus implement its setApplicationEventPublisher method.
This method provides a reference to framework’s ApplicationEventPublisher object which can be used to call its publishEvent() method.

What publishEvent() does is, it takes an object of ApplicationEvent (or its sub-class; PasswordEvent, in our case) and notifies ALL listeners listening for this event type whenever this method (publishEvent()) is called and invokes their onApplicationEvent()method (defined in PasswordChangeEventListener, in our example).

In order to be discovered, this class must be registered as a bean in Spring Application Context. For XML based configuration, it must be declared as a bean in configuration file as :

 <bean id="userOperations" class="com.codippa.spring.UserOperations"/>

or for Annotation based configuration, annotate it with @Component annotation.

Now, let’s test our event mechanism with a Main class.

 public class EventHandling {
	public static void main(String[] args) {
                // get the application context
		ApplicationContext context = 
				new ClassPathXmlApplicationContext("classpath:spring-core-config.xml");
                // get the bean where password change logic is defined
		UserOperations userOperations = context.getBean(UserOperations.class);
                // change password
		userOperations.changePassword();
	}
 }

The output is as expected :

Password Changed
[sc name=”AD2″ ]

Finally, a quick walk-through of the execution flow to grasp the topic in a firm way so that it can be implemented in no-time when required.

  1. Create an event class which extends ApplicationEvent.
  2. Create a listener class which implements ApplicationEventListener and provide an action which needs to be taken when the event occurs in its onApplicationEvent method.
  3. Create a class which contains the method which should generate the event. This class should implement ApplicationEventPublisherAware interface and must implement its setApplicationEventPublisher method to get a reference to Spring’s ApplicationEventPublisher object. Then, from the method which generates the event call publishEvent method on ApplicationEventPublisher object passing it the event object created in Step 1.

Let’s tweak in :

  1. org.springframework.context.ApplicationEvent has a single contructor which accepts an java.lang.Object argument which marks as the source of the event.
  2. org.springframework.context.ApplicationEventhas a timestamp field which marks the time at which the event occurred and may be retrieved using getTimeStamp() method of the event object extending this class.
  3. org.springframework.context.ApplicationListener interface’s onApplicationEvent() method accepts a generic type object and marks the event for which it listens. The object passed to this method must extend  org.springframework.context.ApplicationEvent class.
  4. The type of parameter accepted by onApplicationEvent() is the same which is accepted by org.springframework.context.ApplicationListener. Thus, if ApplicationListener is declared as
    ApplicationListener, then this method will be implemented as onApplicationEvent(PasswordChangeEvent event)
  5. onApplicationEvent() method of org.springframework.context.ApplicationListener is a callback method and is invoked automatically when an event, related to the object for which it is listening, occurs.
  6. setApplicationEventPublisher() method of is a callback method and is automatically invoked by Spring after the class where it is defined (and which extends ApplicationEventPublisherAware) is initialized. For automatic initialization of bean refer this post.

Reached up to this point. Wonderful !!! Don’t go away silently. Mark an impression by providing feedback / queries in the space specifically designed for this.

0

Leave a Reply

Mark Your Impression

  Subscribe  
Notify of
Close Menu

Never Miss an article !

Get the new post delivered straight into your inbox, enter your email and hit the button

You have successfully subscribed to the newsletter

There was an error while trying to send your request. Please try again.

codippa will use the information you provide on this form to be in touch with you and to provide updates and marketing.