Overhaul custom ApplicationEvent documentation (SPR-7422, SPR-7395)

Documentation now:

- Reflects generic use of ApplicationListener interface

- Demonstrates use of ApplicationEventPublisher(Aware) instead of
  ApplicationContext(Aware) for publishing custom events

- Provides a more complete narrative as to how each of the publisher,
  listener, and event objects interact with one another
This commit is contained in:
Chris Beams 2010-08-10 20:59:36 +00:00
parent 720f7ecf48
commit 9008cf907a
1 changed files with 89 additions and 53 deletions

View File

@ -7048,86 +7048,122 @@ argument.required=Ebagum lad, the '{0}' argument is required, I say, required.</
</tgroup> </tgroup>
</table> </table>
<para>You can also implement custom events. Simply call the <para>You can also create and publish your own custom events. This example
<methodname>publishEvent()</methodname> method on the demonstrates a simple class that extends Spring's
<interfacename>ApplicationContext</interfacename>, specifying a <classname>ApplicationEvent</classname> base class:</para>
parameter that is an instance of your custom event class that implements
<classname>ApplicationEvent</classname>. Event listeners receive events
synchronously. This means the <methodname>publishEvent()</methodname>
method blocks until all listeners have finished processing the event.
(It is possible to supply an alternate event publishing strategy through
an <interfacename>ApplicationEventMulticaster</interfacename>
implementation). Furthermore, when a listener receives an event, it
operates inside the transaction context of the publisher, if a
transaction context is available.<!--Explain what is showing in the first and second examples?--></para>
<para>This example shows the bean definitions used to configure an <programlisting language="java">public class BlackListEvent extends ApplicationEvent {
<interfacename>ApplicationContext</interfacename>:</para> private final String address;
private final String test;
<programlisting language="xml">&lt;bean id="emailer" class="example.EmailBean"&gt; public BlackListEvent(Object source, String address, String test) {
&lt;property name="blackList"&gt; super(source);
&lt;list&gt; this.address = address;
&lt;value&gt;black@list.org&lt;/value&gt; this.test = test;
&lt;value&gt;white@list.org&lt;/value&gt; }
&lt;value&gt;john@doe.org&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="blackListListener" class="example.BlackListNotifier"&gt; <lineannotation>// accessor and other methods...</lineannotation>
&lt;property name="notificationAddress" value="spam@list.org"/&gt; }</programlisting>
&lt;/bean&gt;</programlisting>
<para>This example shows the implementation of the classes refered to in <para>To publish a custom <classname>ApplicationEvent</classname>, call
the previous bean definitions:</para> the <methodname>publishEvent()</methodname> method on an
<interfacename>ApplicationEventPublisher</interfacename>. Typically this
is done by creating a class that implements
<interfacename>ApplicationEventPublisherAware</interfacename> and
registering it as a Spring bean. The following example demonstrates such a
class:</para>
<programlisting language="java">public class EmailBean implements ApplicationContextAware { <programlisting language="java"><![CDATA[public class EmailService implements ApplicationEventPublisherAware {
private List blackList; private List<String> blackList;
private ApplicationContext ctx; private ApplicationEventPublisher publisher;
public void setBlackList(List blackList) { public void setBlackList(List<String> blackList) {
this.blackList = blackList; this.blackList = blackList;
} }
public void setApplicationContext(ApplicationContext ctx) { public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
this.ctx = ctx; this.publisher = publisher;
} }
public void sendEmail(String address, String text) { public void sendEmail(String address, String text) {
if (blackList.contains(address)) { if (blackList.contains(address)) {
BlackListEvent event = new BlackListEvent(address, text); BlackListEvent event = new BlackListEvent(this, address, text);
ctx.publishEvent(event); publisher.publishEvent(event);
return; return;
} }
<lineannotation>// send email...</lineannotation> ]]><lineannotation>// send email...</lineannotation><![CDATA[
} }
}</programlisting> }]]></programlisting>
<programlisting language="java">public class BlackListNotifier implements ApplicationListener { <para>At configuration time, the Spring container will detect that
<classname>EmailService</classname> implements
<interfacename>ApplicationEventPublisherAware</interfacename> and will
automatically call
<methodname>setApplicationEventPublisher()</methodname>. In reality, the
parameter passed in will be the Spring container itself; you're simply
interacting with the application context via its
<interfacename>ApplicationEventPublisher</interfacename>
interface.</para>
<para>To receive the custom <classname>ApplicationEvent</classname>,
create a class that implements
<interfacename>ApplicationListener</interfacename> and register it as a
Spring bean. The following example demonstrates such a class:</para>
<programlisting language="java"><![CDATA[public class BlackListNotifier implements ApplicationListener<BlackListEvent> {
private String notificationAddress; private String notificationAddress;
public void setNotificationAddress(String notificationAddress) { public void setNotificationAddress(String notificationAddress) {
this.notificationAddress = notificationAddress; this.notificationAddress = notificationAddress;
} }
public void onApplicationEvent(ApplicationEvent event) { public void onApplicationEvent(BlackListEvent event) {
if (event instanceof BlackListEvent) { ]]><lineannotation> // notify appropriate parties via notificationAddress...</lineannotation><![CDATA[
<lineannotation>// notify appropriate person...</lineannotation>
}
} }
}</programlisting> }]]></programlisting>
<!-- MLP: Beverly to review paragraph --> <para>Notice that <interfacename>ApplicationListener</interfacename> is
generically parameterized with the type of your custom event,
<classname>BlackListEvent</classname>. This means that the
<methodname>onApplicationEvent()</methodname> method can remain
type-safe, avoiding any need for downcasting. You may register as many
event listeners as you wish, but note that by default event listeners
receive events synchronously. This means the
<methodname>publishEvent()</methodname> method blocks until all
listeners have finished processing the event. One advantage of this
synchronous and single-threaded approach is that when a listener
receives an event, it operates inside the transaction context of the
publisher if a transaction context is available. If another strategy for
event publication becomes necessary, refer to the JavaDoc for Spring's
<interfacename>ApplicationEventMulticaster</interfacename>
interface.</para>
<para>When the sendEmail method is called, if there are any emails that <para>The following example demonstrates the bean definitions used to
should be blacklisted, a custom event of the type BlackListEvent is register and configure each of the classes above:</para>
published to the application context. The BlackListNotifier class which <programlisting language="xml"><![CDATA[<bean id="emailService" class="example.EmailService">
implements the interface ApplicationListener is registered as a <property name="blackList">
subscriber to the application context and will receive the <list>
BlackListEvent. In order to access properties specific to <value>black@list.org</value>
BlackListEvent, the listener must perform a downcast.</para> <value>white@list.org</value>
<value>john@doe.org</value>
</list>
</property>
</bean>
<bean id="blackListNotifier" class="example.BlackListNotifier">
<property name="notificationAddress" value="spam@list.org"/>
</bean>]]></programlisting>
<para>Putting it all together, when the <methodname>sendEmail()</methodname>
method of the <literal>emailService</literal> bean is called, if there
are any emails that should be blacklisted, a custom event of type
<classname>BlackListEvent</classname> is published. The
<literal>blackListNotifier</literal> bean is registered as an
<interfacename>ApplicationListener</interfacename> and thus receives the
<classname>BlackListEvent</classname>, at which point it can notify
appropriate parties.</para>
</section> </section>
<section id="context-functionality-resources"> <section id="context-functionality-resources">