Observer Pattern with Spring Events
The essence of the Observer Pattern is to ‘Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.’ GoF. Observer pattern is a subset of publish/subscribe pattern which allows a number of observer objects to see an event.
This pattern can be used in different situations, but in summary we can say that Observer pattern can be applied when an object should be able to notify messages to other objects, and you don’t want these objects being tightly coupled. In my case I have used this pattern when an asynchronous event should be notified to one or more graphical component.
This pattern can be implemented using an adhoc solution or using java.util.Observer/Observable classes. But my projects are always developed with Spring whether they are web or desktop applications. So in current post I will explain how I implement Observer pattern with Spring.
HANDS ON
Event handling in Spring ApplicationContext is provided through ApplicationEvent class and ApplicationListener interface. If a bean that implements ApplicationListener interface is deployed into the context, every time an ApplicationEvent is published to container, ApplicationListener receives it.
Spring comes with built-in events, like ContextStartedEvent, ContextStoppedEvent, but you can also create your own custom events.
For developing your own events, three classes are required, observer role, observable role and the event. Observers are those who receive events and must implement ApplicationListener class. Observable classes are responsible of publishing events and must implement ApplicationEventPublisherAware. Finally event class has to extend ApplicationEvent.
CODING
What I am going to implement is wikipedia example of Observer pattern ( http://en.wikipedia.org/wiki/Observer_pattern#Example) but using Spring Events instead of Observer/Observable Java classes. The example is a basic publish/subscribe example where one String message is sent from one module to another one.
Let’s create MessageEvent. This event contains a String that represents the message we want to send. It is a simple class that extends from ApplicationEvent.
public class MessageEvent extends ApplicationEvent { ** * * private static final long serialVersionUID = 5743058377815147529L; private String message; public MessageEvent(Object source, String message) { super(source); this.message = message; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append('MessageEvent [message=').append(message).append(']'); return builder.toString(); } }
Next class is the Observable class. This class must implements ApplicationEventPublisherAware. This interface defines a setter method with ApplicationEventPublisher as parameter. This parameter is used for publishing events.
In current implementation see that also implements Runnable interface so user can create from console input,
public class EventSource implements Runnable, ApplicationEventPublisherAware { private ApplicationEventPublisher applicationEventPublisher = null; public void setApplicationEventPublisher( ApplicationEventPublisher applicationEventPublisher) { this.applicationEventPublisher = applicationEventPublisher; } public void run() { final InputStreamReader isr = new InputStreamReader(System.in); final BufferedReader br = new BufferedReader(isr); while (true) { try { String response = br.readLine(); System.out.println(Thread.currentThread().getName()); this.applicationEventPublisher.publishEvent(new MessageEvent(this, response)); } catch (IOException e) { e.printStackTrace(); } } } }
The Observer class is even simpler. Implements ApplicationListener interface. Method onApplicationEvent is called when an event is published. See that it is a generic interface, so no cast is required. This differs from java.util.Observer class.
public class ResponseHandler implements ApplicationListener<MessageEvent> { public void onApplicationEvent(MessageEvent messageEvent) { System.out.println(Thread.currentThread().getName()); System.out.println(messageEvent); } }
In application context file, you register both ApplicationListener and ApplicationEventPublisherAware beans.
And finally a main class to test the system. A thread is created to execute multiple asynchronous events.
public class MyApp { public static void main(String args[]) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext('classpath:META-INFspringapp-context.xml'); EventSource eventSource = applicationContext.getBean('eventSource', EventSource.class); Thread thread = new Thread(eventSource); thread.start(); } }
So start the program and write something to console. You will see something like:
hello Thread-0 Thread-0 MessageEvent [message=hello]
I have entered ‘ hello‘ message and thread name of event publisher is printed. Then event is sent and handler thread name is printed too. Finally the received event is shown. There is one thing that should call your attention. Both sender ( Observable) and receiver ( Observer) are executed in same thread; by default event listeners receive events synchronously. This means that publishEvent() method, blocks until all listeners have finished processing the event. This approach has many advantages (for example reusing transaction contexts, …), but in some cases you will prefer that each event is executed in new thread, Spring also supports this strategy.
In Spring, class responsible of managing events is SimpleApplicationEventMulticaster. This class multicasts all events to all registered listeners, leaving it up to the listeners to ignore events that they are not interested in. Default behaviour is that all listeners are invoked in calling thread.
Now I am going to explain how Spring Event Architecture is initialized and how you can modify. By default when ApplicationContext is started up, it calls initApplicationEventMulticaster method. This method verify if exists a bean with id applicationEventMulticaster of type ApplicationEventMulticaster. If it is the case defined ApplicationEventMulticaster is used, if not a new SimpleApplicationEventMulticaster with default configuration is created.
SimpleApplicationEventMulticaster has a setTaskExecutor which can be used for specifying which java.util.concurrent.Executor will execute events. So if you want that each event is executed in a different thread, a good approach would be using a ThreadPoolExecutor. As explained in last paragraph, now we must explicitly define SimpleApplicationEventMulticaster instead of using default ones. Let’s implement:
<beans xmlns='http:www.springframework.orgschemabeans' xmlns:xsi='http:www.w3.org2001XMLSchema-instance' xmlns:context='http:www.springframework.orgschemacontext' xmlns:task='http:www.springframework.orgschematask' xsi:schemaLocation='http:www.springframework.orgschematask http:www.springframework.orgschemataskspring-task-3.0.xsd http:www.springframework.orgschemabeans http:www.springframework.orgschemabeansspring-beans-3.0.xsd http:www.springframework.orgschemacontext http:www.springframework.orgschemacontextspring-context-3.0.xsd'> <bean id='eventSource' class='org.asotobu.oo.EventSource' > <bean id='responseHandler' class='org.asotobu.oo.ResponseHandler' > <task:executor id='pool' pool-size='10' > <bean id='applicationEventMulticaster' class='org.springframework.context.event.SimpleApplicationEventMulticaster'> <property name='taskExecutor' ref='pool' > <bean> <beans>
First of all SimpleApplicationEventMulticaster must be defined as a bean with id applicationEventMulticaster. Then task pool is set, and we rerun our main class. And output will be:
hello Thread-1 pool-1 MessageEvent [message=hello]
Note that now sender and receiver thread is different.
And of course you can create your own ApplicationEventMulticaster for more complex operations. You just have to implement ApplicationEventMulticaster and defining it with applicationEventMulticaster bean name, and events will be executed depending on your own strategy.
Hope that now your Spring desktop applications can take full advantage of Spring events for separating modules.
Reference: Observer Pattern with Spring Events from our JCG partner Alex Soto at the One Jar To Rule Them All blog.
Spring supports either sync or async event publishing in an ApplicationContext. Is there any way to make it support both sync and async event emitting in single context?