Easy Event-Driven Application With Spring!

On November 5, 2009, in Java, Spring, by Jan-Hendrik Kuperus

Suppose you are making an event-driven application. You have your listener interfaces and your event-generating objects. What is the most annoying part of getting this all to work?

Connecting your listeners to the event-generating objects. Every time you want some object to receive certain events, you have to register your listener with the correct producer object. This has some nasty effects on your code:

  • Either your listeners know to which object they are subscribing, or your event generators know who should be listening to their events
  • Due to this coupling, listeners and producers are difficult to test
  • Adding a new listener to your project requires some boilerplate code to get it working

Spring has a feature that can take care of all of this hassle: autowiring. For normal dependency injection, autowiring feels icky. It’s just too magical and leaves me with a feeling I am not in control. The great thing about autowiring is that it can be used on a per-method base.

Suppose you have a listener interface:

public interface MyEventListener
{
  public void onMyEvent(MyEvent me);
}

And suppose you have some class that implements this interface:

public class MyListener implements MyEventListener
{
  public void onMyEvent(MyEvent me)
  {
    System.out.println("My Event was raised!");
  }
}

Cool, so now we still need some event-generating class:

public class MyGenerator
{
  private MyEventListener[] listeners;

  public void generateEvent()
  {
    MyEvent me = new MyEvent();

    for (MyEventListener mel: listeners)
    {
      mel.onMyEvent(me);
    }
  }

  public void setMyEventListeners(MyEventListener[] listeners)
  {
    this.listeners = listeners;
  }
}

If you looked at the above class and wondered why I’ve made a setter for an array of listeners, instead of a method that registers a single listener, then prepare to be amazed. If you are familiar with Spring and autowiring, you probably know where I am headed :) .

Neither the event listener, nor the event generator have any knowledge of each other. This is perfect, we can write unittests for each class without having to mock the other. However, the event generator still needs a reference to the listener for this thing to work. Let’s put these two objects in a Spring context together:

<beans ...>

  <bean name="myGenerator" class="MyEventGenerator"/>

  <bean name="myListener" class="MyListener"/>

</beans>

Great! Almost there, all we need now is some magic. The magic requires two components, one in the Spring config and one in the event generator class. The Spring config requires the <context:annotation-config/> tag, to enable the annotations:

<beans ...>

  <context:annotation-config/>

  ...

</beans>

And finally, the generator class will get its listeners autowired:

  @Autowire(required=false)
  public void setMyEventListeners(MyEventListener[] listeners)
  {
    this.listeners = listeners;
  }

Tada! The generator class will now automatically have an array of listeners injected into its setter. The Spring container selects all beans that are assignable to the array value type and passes them to the event generator. The required = false bit ensures Spring won’t throw an exception when you have no listeners configured.

If you now want more than one bean to listen to these events, all you have to do is add a bean to the Spring config that implements the MyEventListener interface and it will automatically get added to the array. Yes, it is really that simple.

Have fun!

–JH

 

3 Responses to Easy Event-Driven Application With Spring!

  1. Good news: Your tutorial solved my problem with this 100%. Bad news: The solution is so easy that it makes me feel like a techno-dweeb. Keep up the hard work on your site. Oh well, at least I won’t get toasted for not being able to make this work now :) You’re my newest idol.

    • Hi, good to hear my braindumps actually help people! Don’t feel too bad about yourself, we usually tend to think way too complicated and get ourselves in trouble. Just keep having fun coding :)

      –JH

  2. [...] The events were distributed to components by Spring using the technique described in an earlier post of mine. When the time came to develop a user interface, we decided to give JavaFX a try (the blue [...]

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>