提交 0b84f137 编写于 作者: S Stephane Nicoll

Document application event improvements

Issue: SPR-12702
上级 e6f99ffe
......@@ -7351,7 +7351,7 @@ package also provides the following functionality:
* __Access to messages in i18n-style__, through the `MessageSource` interface.
* __Access to resources__, such as URLs and files, through the `ResourceLoader` interface.
* __Event publication__ to beans implementing the `ApplicationListener` interface,
* __Event publication__ to namely beans implementing the `ApplicationListener` interface,
through the use of the `ApplicationEventPublisher` interface.
* __Loading of multiple (hierarchical) contexts__, allowing each to be focused on one
particular layer, such as the web layer of an application, through the
......@@ -7571,8 +7571,18 @@ Event handling in the `ApplicationContext` is provided through the `ApplicationE
class and `ApplicationListener` interface. If a bean that implements the
`ApplicationListener` interface is deployed into the context, every time an
`ApplicationEvent` gets published to the `ApplicationContext`, that bean is notified.
Essentially, this is the standard __Observer__ design pattern. Spring provides the
following standard events:
Essentially, this is the standard __Observer__ design pattern.
[TIP]
====
As of Spring 4.2, the event infrastructure has been significantly improved and offer
an <<context-functionality-events-annotation,annotation-based model>> as well as the
ability to publish any arbitrary event, that is an object that does not necessarily
extend from `ApplicationEvent`. When such an object is published we wrap it in a
`PayloadApplicationEvent` for you.
====
Spring provides the following standard events:
[[beans-ctx-events-tbl]]
.Built-in Events
......@@ -7747,6 +7757,97 @@ http://www.enterpriseintegrationpatterns.com[pattern-oriented], event-driven
architectures that build upon the well-known Spring programming model.
====
[[context-functionality-events-annotation]]
==== Annotation-based Event Listeners
As of Spring 4.2, an event listener can be registered on any public method of a managed
bean via the `EventListener` annotation. The `BlackListNotifier` can be rewritten as
follows:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
public class BlackListNotifier {
private String notificationAddress;
public void setNotificationAddress(String notificationAddress) {
this.notificationAddress = notificationAddress;
}
@EventListener
public void processBlackListEvent(BlackListEvent event) {
// notify appropriate parties via notificationAddress...
}
}
----
As you can see above, the method signature actually _infer_ which even type it listens to. This
also works for nested generics as long as the actual event resolves the generics parameter you
would filter on.
It is also possible to add additional runtime filtering via the `condition` attribute of the
annotation that defines a <<expressions,`SpEL` expression>> that should match to actually invoke
the method for a particular event.
For instance, our notifier can be rewritten to be only invoked if the `test` attribute of the
event is equal to `foo`:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@EventListener(condition = "#event.test == 'foo'")
public void processBlackListEvent(BlackListEvent event) {
// notify appropriate parties via notificationAddress...
}
----
Each `SpEL` expression evaluates again a dedicated context. The next table lists the items made
available to the context so one can use them for conditional event processing:
[[context-functionality-events-annotation-tbl]]
.Event SpEL available metadata
|===
| Name| Location| Description| Example
| event
| root object
| The actual `ApplicationEvent`
| `#root.event`
| args
| root object
| The arguments (as array) used for invoking the target
| `#root.args[0]`
| __argument name__
| evaluation context
| Name of any of the method argument. If for some reason the names are not available
(ex: no debug information), the argument names are also available under the `a<#arg>`
where __#arg__ stands for the argument index (starting from 0).
| `iban` or `a0` (one can also use `p0` or `p<#arg>` notation as an alias).
|===
Note that `#root.event` allows you to access to the underlying event, even if your method
signature actually refers to an arbitrary object that was published.
If you need to publish an event as the result of processing another, just change the
method signature to return the event that should be published, something like:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@EventListener
public ListUpdateEvent handleBlackListEvent(BlackListEvent event) {
// notify appropriate parties via notificationAddress and
// then publish a ListUpdateEvent...
}
----
This new method will publish a new `ListUpdateEvent` for every `BlackListEvent` handled
by the method above. If you need to publish several events, just return a `Collection` of
events instead.
[[context-functionality-resources]]
......
......@@ -54,6 +54,8 @@ server integration, and solutions to common problems.)
declarative transaction management.
* <<transaction-programmatic,Programmatic transaction management>> covers support for
programmatic (that is, explicitly coded) transaction management.
* <<transaction-event,Transaction bound event>> describes how you could use application
events within a transaction.
......@@ -1924,8 +1926,44 @@ management out of business logic, and is not difficult to configure. When using
Spring Framework, rather than EJB CMT, the configuration cost of declarative transaction
management is greatly reduced.
[[transaction-event]]
=== Transaction bound event
As of Spring 4.2, the listener of an event can be bound to a phase of the transaction. The
typical example is to handle the event when the transaction has completed successfully: this
allows events to be used with more flexibility when the outcome of the current transaction
actually matters to the listener.
Registering a regular event listener is done via the `@EventListener` annotation. If you need
to bind it to the transaction use `@TransactionalEventListener`. When you do so, the listener
will be bound to the commit phase of the transaction by default.
Let's take an example to illustrate this concept. Assume that a component publish an order
created event and we want to define a listener that should only handle that event once the
transaction in which it has been published as committed successfully:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@Component
public class MyComponent {
@TransactionalEventListener
public void handleOrderCreatedEvent(CreationEvent<Order> creationEvent) {
...
}
}
----
The `TransactionalEventListener` annotation exposes a `phase` attribute that allows to customize
to which phase of the transaction the listener should be bound to. The valid phases are `BEFORE_COMMIT`,
`AFTER_COMMIT` (default), `AFTER_ROLLBACK` and `AFTER_COMPLETION` that aggregates the transaction
completion (be it a commit or a rollback).
If no transaction is running, the listener is not invoked at all since we can't honor the required
semantics. It is however possible to override that behaviour by setting the `fallbackExecution` attribute
of the annotation to `true`.
[[transaction-application-server-integration]]
=== Application server-specific integration
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册