0
# Event Handling
1
2
Application event system providing publish-subscribe functionality for decoupled communication between components. This includes @EventListener annotations, event publishing, multicasting, and both synchronous and asynchronous event processing with conditional handling.
3
4
## Capabilities
5
6
### Event Listener Annotations
7
8
Declarative event handling through annotations that automatically register methods as event listeners.
9
10
```java { .api }
11
/**
12
* Annotation that marks a method as a listener for application events.
13
* If an annotated method supports a single event type, the method may
14
* declare a single parameter that reflects the event type to listen to.
15
*/
16
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
17
@Retention(RetentionPolicy.RUNTIME)
18
public @interface EventListener {
19
/**
20
* Alias for classes().
21
* @return the event classes to handle
22
*/
23
@AliasFor("classes")
24
Class<?>[] value() default {};
25
26
/**
27
* The event classes that this listener handles.
28
* @return the event classes to handle
29
*/
30
@AliasFor("value")
31
Class<?>[] classes() default {};
32
33
/**
34
* Spring Expression Language (SpEL) expression used for making the event handling conditional.
35
* @return the condition expression
36
*/
37
String condition() default "";
38
39
/**
40
* An optional identifier for the listener, defaulting to the fully-qualified signature of the declaring method.
41
* @return the listener identifier
42
*/
43
String id() default "";
44
}
45
```
46
47
### Application Event Infrastructure
48
49
Core interfaces and classes for the event system foundation.
50
51
```java { .api }
52
/**
53
* Class to be extended by all application events.
54
* Abstract as it doesn't make sense for generic events to be published directly.
55
*/
56
public abstract class ApplicationEvent extends EventObject {
57
/** System time when the event happened */
58
private final long timestamp;
59
60
/**
61
* Create a new ApplicationEvent.
62
* @param source the object on which the event initially occurred (never null)
63
*/
64
public ApplicationEvent(Object source) {}
65
66
/**
67
* Return the system time in milliseconds when the event happened.
68
* @return the system time when the event happened
69
*/
70
public final long getTimestamp() {}
71
}
72
73
/**
74
* ApplicationEvent that carries an arbitrary payload.
75
* Mainly intended for internal use within the framework.
76
*/
77
public class PayloadApplicationEvent<T> extends ApplicationEvent implements ResolvableTypeProvider {
78
private final T payload;
79
80
/**
81
* Create a new PayloadApplicationEvent.
82
* @param source the object on which the event initially occurred (never null)
83
* @param payload the payload object (never null)
84
*/
85
public PayloadApplicationEvent(Object source, T payload) {}
86
87
/**
88
* Return the payload of this event.
89
* @return the payload object
90
*/
91
public T getPayload() {}
92
93
/**
94
* Return the ResolvableType describing the generic type of the payload.
95
* @return the ResolvableType describing the payload type
96
*/
97
public ResolvableType getResolvableType() {}
98
}
99
100
/**
101
* Interface to be implemented by application event listeners.
102
*/
103
@FunctionalInterface
104
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
105
/**
106
* Handle an application event.
107
* @param event the event to respond to
108
*/
109
void onApplicationEvent(E event);
110
111
/**
112
* Determine whether this listener actually supports asynchronous execution.
113
* @return whether this listener supports asynchronous execution
114
*/
115
default boolean supportsAsyncExecution() {
116
return true;
117
}
118
}
119
```
120
121
### Event Publishing
122
123
Interfaces for publishing events to registered listeners.
124
125
```java { .api }
126
/**
127
* Interface that encapsulates event publication functionality.
128
* Serves as a super-interface for ApplicationContext.
129
*/
130
public interface ApplicationEventPublisher {
131
/**
132
* Notify all matching listeners registered with this application of an application event.
133
* @param event the event to publish
134
*/
135
default void publishEvent(ApplicationEvent event) {
136
publishEvent((Object) event);
137
}
138
139
/**
140
* Notify all matching listeners registered with this application of an event.
141
* @param event the event to publish (may be framework events or application-specific events)
142
*/
143
void publishEvent(Object event);
144
}
145
146
/**
147
* Interface to be implemented by objects that wish to be notified of the ApplicationEventPublisher.
148
*/
149
public interface ApplicationEventPublisherAware extends Aware {
150
/**
151
* Set the ApplicationEventPublisher that this object runs in.
152
* @param applicationEventPublisher event publisher to be used by this object
153
*/
154
void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher);
155
}
156
```
157
158
### Event Multicasting
159
160
Infrastructure for distributing events to multiple listeners with support for synchronous and asynchronous execution.
161
162
```java { .api }
163
/**
164
* Interface to be implemented by objects that can manage a number of ApplicationListener objects
165
* and publish events to them.
166
*/
167
public interface ApplicationEventMulticaster {
168
/**
169
* Add a listener to be notified of all events.
170
* @param listener the listener to add
171
*/
172
void addApplicationListener(ApplicationListener<?> listener);
173
174
/**
175
* Add a listener bean to be notified of all events.
176
* @param listenerBeanName the name of the listener bean to add
177
*/
178
void addApplicationListenerBean(String listenerBeanName);
179
180
/**
181
* Remove a listener from the notification list.
182
* @param listener the listener to remove
183
*/
184
void removeApplicationListener(ApplicationListener<?> listener);
185
186
/**
187
* Remove a listener bean from the notification list.
188
* @param listenerBeanName the name of the listener bean to remove
189
*/
190
void removeApplicationListenerBean(String listenerBeanName);
191
192
/**
193
* Remove all matching ApplicationListener objects from the set of listeners
194
* managed by this multicaster.
195
* @param predicate the predicate to apply to listener candidates
196
*/
197
void removeApplicationListeners(Predicate<ApplicationListener<?>> predicate);
198
199
/**
200
* Remove all matching ApplicationListener bean names from the set of listener bean names
201
* managed by this multicaster.
202
* @param predicate the predicate to apply to listener bean name candidates
203
*/
204
void removeApplicationListenerBeans(Predicate<String> predicate);
205
206
/**
207
* Remove all listeners registered with this multicaster.
208
*/
209
void removeAllListeners();
210
211
/**
212
* Multicast the given application event to appropriate listeners.
213
* @param event the event to multicast
214
*/
215
void multicastEvent(ApplicationEvent event);
216
217
/**
218
* Multicast the given application event to appropriate listeners.
219
* @param event the event to multicast
220
* @param eventType the type of event (can be null)
221
*/
222
void multicastEvent(ApplicationEvent event, ResolvableType eventType);
223
}
224
225
/**
226
* Simple implementation of the ApplicationEventMulticaster interface.
227
* Multicasts all events to all registered listeners, leaving it up to the listeners
228
* to ignore events that they are not interested in.
229
*/
230
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
231
private Executor taskExecutor;
232
private ErrorHandler errorHandler;
233
234
/**
235
* Set a custom executor (typically a TaskExecutor) to invoke each listener with.
236
* @param taskExecutor a custom executor (may be null for synchronous processing)
237
*/
238
public void setTaskExecutor(Executor taskExecutor) {}
239
240
/**
241
* Set the ErrorHandler to invoke in case an exception is thrown from a listener.
242
* @param errorHandler the ErrorHandler to invoke
243
*/
244
public void setErrorHandler(ErrorHandler errorHandler) {}
245
246
/**
247
* Multicast the given application event to appropriate listeners.
248
* @param event the event to multicast
249
*/
250
public void multicastEvent(ApplicationEvent event) {}
251
252
/**
253
* Multicast the given application event to appropriate listeners.
254
* @param event the event to multicast
255
* @param eventType the type of event (can be null)
256
*/
257
public void multicastEvent(ApplicationEvent event, ResolvableType eventType) {}
258
}
259
```
260
261
### Advanced Listener Interfaces
262
263
Extended listener interfaces providing additional functionality for event filtering and ordering.
264
265
```java { .api }
266
/**
267
* Extended variant of the standard ApplicationListener interface,
268
* exposing further metadata such as the supported event and source type.
269
*/
270
public interface SmartApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {
271
/**
272
* Determine whether this listener actually supports the given event type.
273
* @param eventType the event type (never null)
274
* @return whether this listener supports the event type
275
*/
276
boolean supportsEventType(Class<? extends ApplicationEvent> eventType);
277
278
/**
279
* Determine whether this listener actually supports the given source type.
280
* @param sourceType the source type, or null if no source
281
* @return whether this listener supports the source type
282
*/
283
default boolean supportsSourceType(Class<?> sourceType) {
284
return true;
285
}
286
287
/**
288
* Determine this listener's order in a set of listeners for the same event.
289
* @return the order value (the lower, the higher the priority)
290
*/
291
default int getOrder() {
292
return LOWEST_PRECEDENCE;
293
}
294
295
/**
296
* Return an optional identifier for the listener.
297
* @return the identifier (or null for no specific identifier)
298
*/
299
default String getListenerId() {
300
return null;
301
}
302
}
303
304
/**
305
* Extended variant of the standard ApplicationListener interface, exposing further
306
* metadata such as the supported event and source type.
307
*/
308
public interface GenericApplicationListener extends SmartApplicationListener {
309
/**
310
* Determine whether this listener actually supports the given event type.
311
* @param eventType the event type (as ResolvableType)
312
* @return whether this listener supports the event type
313
*/
314
boolean supportsEventType(ResolvableType eventType);
315
316
/**
317
* Determine whether this listener actually supports the given source type.
318
* @param sourceType the source type, or null if no source
319
* @return whether this listener supports the source type
320
*/
321
boolean supportsSourceType(Class<?> sourceType);
322
323
/**
324
* Determine this listener's order in a set of listeners for the same event.
325
* @return the order value (the lower, the higher the priority)
326
*/
327
int getOrder();
328
329
/**
330
* Return an optional identifier for the listener.
331
* @return the identifier (or null for no specific identifier)
332
*/
333
String getListenerId();
334
}
335
```
336
337
### Event Listener Factory
338
339
Infrastructure for creating event listeners from @EventListener methods.
340
341
```java { .api }
342
/**
343
* Strategy interface for creating ApplicationListener instances for methods
344
* annotated with @EventListener.
345
*/
346
public interface EventListenerFactory {
347
/**
348
* Specify if this factory supports the specified Method.
349
* @param method a Method instance
350
* @return whether this factory supports the specified method
351
*/
352
boolean supportsMethod(Method method);
353
354
/**
355
* Create an ApplicationListener for the specified method.
356
* @param beanName the name of the bean
357
* @param type the target type of the instance
358
* @param method the Method to invoke
359
* @return an ApplicationListener wrapping the method
360
*/
361
ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method);
362
}
363
364
/**
365
* Default EventListenerFactory implementation that supports the regular
366
* @EventListener annotation.
367
*/
368
public class DefaultEventListenerFactory implements EventListenerFactory, Ordered {
369
private int order = LOWEST_PRECEDENCE;
370
371
/**
372
* Set the order value for this factory.
373
* @param order the order value
374
*/
375
public void setOrder(int order) {}
376
377
/**
378
* Specify if this factory supports the specified Method.
379
* @param method a Method instance
380
* @return whether this factory supports the specified method
381
*/
382
public boolean supportsMethod(Method method) {}
383
384
/**
385
* Create an ApplicationListener for the specified method.
386
* @param beanName the name of the bean
387
* @param type the target type of the instance
388
* @param method the Method to invoke
389
* @return an ApplicationListener wrapping the method
390
*/
391
public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {}
392
393
/**
394
* Return the order value for this factory.
395
* @return the order value
396
*/
397
public int getOrder() {}
398
}
399
```
400
401
### Built-in Context Events
402
403
Standard ApplicationContext events published during the context lifecycle.
404
405
```java { .api }
406
/**
407
* Base class for events raised for an ApplicationContext.
408
*/
409
public abstract class ApplicationContextEvent extends ApplicationEvent {
410
/**
411
* Create a new ContextStartedEvent.
412
* @param source the ApplicationContext that the event is raised for (must not be null)
413
*/
414
public ApplicationContextEvent(ApplicationContext source) {}
415
416
/**
417
* Get the ApplicationContext that the event was raised for.
418
* @return the ApplicationContext (never null)
419
*/
420
public final ApplicationContext getApplicationContext() {}
421
}
422
423
/**
424
* Event raised when an ApplicationContext gets initialized or refreshed.
425
*/
426
public class ContextRefreshedEvent extends ApplicationContextEvent {
427
/**
428
* Create a new ContextRefreshedEvent.
429
* @param source the ApplicationContext that has been initialized or refreshed (must not be null)
430
*/
431
public ContextRefreshedEvent(ApplicationContext source) {}
432
}
433
434
/**
435
* Event raised when an ApplicationContext gets started.
436
*/
437
public class ContextStartedEvent extends ApplicationContextEvent {
438
/**
439
* Creates a new ContextStartedEvent.
440
* @param source the ApplicationContext that has been started (must not be null)
441
*/
442
public ContextStartedEvent(ApplicationContext source) {}
443
}
444
445
/**
446
* Event raised when an ApplicationContext gets stopped.
447
*/
448
public class ContextStoppedEvent extends ApplicationContextEvent {
449
/**
450
* Creates a new ContextStoppedEvent.
451
* @param source the ApplicationContext that has been stopped (must not be null)
452
*/
453
public ContextStoppedEvent(ApplicationContext source) {}
454
}
455
456
/**
457
* Event raised when an ApplicationContext gets closed.
458
*/
459
public class ContextClosedEvent extends ApplicationContextEvent {
460
/**
461
* Creates a new ContextClosedEvent.
462
* @param source the ApplicationContext that has been closed (must not be null)
463
*/
464
public ContextClosedEvent(ApplicationContext source) {}
465
}
466
```
467
468
### Event Processing Infrastructure
469
470
Classes supporting event listener registration and method adaptation.
471
472
```java { .api }
473
/**
474
* ApplicationListener adapter that delegates the handling of an ApplicationEvent
475
* to a target method annotated with @EventListener.
476
*/
477
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {
478
/**
479
* Handle an application event.
480
* @param event the event to respond to
481
*/
482
public void onApplicationEvent(ApplicationEvent event) {}
483
484
/**
485
* Determine whether this listener actually supports the given event type.
486
* @param eventType the event type (as ResolvableType)
487
* @return whether this listener supports the event type
488
*/
489
public boolean supportsEventType(ResolvableType eventType) {}
490
491
/**
492
* Determine whether this listener actually supports the given source type.
493
* @param sourceType the source type, or null if no source
494
* @return whether this listener supports the source type
495
*/
496
public boolean supportsSourceType(Class<?> sourceType) {}
497
498
/**
499
* Determine this listener's order in a set of listeners for the same event.
500
* @return the order value (the lower, the higher the priority)
501
*/
502
public int getOrder() {}
503
504
/**
505
* Return an identifier for the listener.
506
* @return the identifier
507
*/
508
public String getListenerId() {}
509
}
510
511
/**
512
* BeanPostProcessor that processes beans with @EventListener annotations.
513
*/
514
public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {
515
/**
516
* Post-process the given bean factory.
517
* @param beanFactory the bean factory used by the application context
518
* @throws BeansException in case of errors
519
*/
520
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
521
522
/**
523
* Invoked right at the end of the singleton pre-instantiation phase,
524
* with a guarantee that all regular singleton beans have been created already.
525
*/
526
public void afterSingletonsInstantiated() {}
527
528
/**
529
* Process the specified bean, detecting @EventListener methods and registering ApplicationListeners for them.
530
* @param beanName the name of the bean
531
* @param targetType the type of the bean
532
*/
533
protected void processBean(String beanName, Class<?> targetType) {}
534
}
535
```
536
537
### Usage Examples
538
539
**Basic Event Listener:**
540
541
```java
542
import org.springframework.context.event.EventListener;
543
import org.springframework.stereotype.Component;
544
545
@Component
546
public class UserEventListener {
547
548
@EventListener
549
public void handleUserCreated(UserCreatedEvent event) {
550
System.out.println("User created: " + event.getUser().getName());
551
// Send welcome email, update statistics, etc.
552
}
553
554
@EventListener
555
public void handleUserDeleted(UserDeletedEvent event) {
556
System.out.println("User deleted: " + event.getUserId());
557
// Clean up user data, send notifications, etc.
558
}
559
560
// Listen to multiple event types
561
@EventListener({UserCreatedEvent.class, UserUpdatedEvent.class})
562
public void handleUserChanges(UserEvent event) {
563
System.out.println("User changed: " + event.getUser().getName());
564
}
565
}
566
567
// Custom event classes
568
public class UserCreatedEvent extends ApplicationEvent {
569
private final User user;
570
571
public UserCreatedEvent(Object source, User user) {
572
super(source);
573
this.user = user;
574
}
575
576
public User getUser() {
577
return user;
578
}
579
}
580
581
public class UserDeletedEvent extends ApplicationEvent {
582
private final Long userId;
583
584
public UserDeletedEvent(Object source, Long userId) {
585
super(source);
586
this.userId = userId;
587
}
588
589
public Long getUserId() {
590
return userId;
591
}
592
}
593
```
594
595
**Conditional Event Handling:**
596
597
```java
598
@Component
599
public class ConditionalEventListener {
600
601
// Only handle events when user is premium
602
@EventListener(condition = "#event.user.isPremium()")
603
public void handlePremiumUserEvent(UserCreatedEvent event) {
604
System.out.println("Premium user created: " + event.getUser().getName());
605
// Send premium welcome package
606
}
607
608
// Handle events based on application properties
609
@EventListener(condition = "@environment.getProperty('notifications.enabled') == 'true'")
610
public void handleNotificationEvent(NotificationEvent event) {
611
// Send notification only if enabled in configuration
612
sendNotification(event.getMessage());
613
}
614
615
// Conditional handling with SpEL expressions
616
@EventListener(condition = "#event.severity > 5")
617
public void handleCriticalAlerts(AlertEvent event) {
618
// Only handle critical alerts (severity > 5)
619
escalateAlert(event);
620
}
621
}
622
```
623
624
**Event Publishing:**
625
626
```java
627
import org.springframework.context.ApplicationEventPublisher;
628
import org.springframework.beans.factory.annotation.Autowired;
629
import org.springframework.stereotype.Service;
630
631
@Service
632
public class UserService {
633
634
@Autowired
635
private ApplicationEventPublisher eventPublisher;
636
637
public User createUser(String name, String email) {
638
User user = new User(name, email);
639
// Save user to database
640
userRepository.save(user);
641
642
// Publish event
643
UserCreatedEvent event = new UserCreatedEvent(this, user);
644
eventPublisher.publishEvent(event);
645
646
return user;
647
}
648
649
public void deleteUser(Long userId) {
650
// Delete user from database
651
userRepository.deleteById(userId);
652
653
// Publish event using object (PayloadApplicationEvent will be created automatically)
654
eventPublisher.publishEvent(new UserDeletedEvent(this, userId));
655
}
656
657
// Publishing arbitrary objects as events
658
public void processOrder(Order order) {
659
// Process the order
660
661
// Publish simple string as event
662
eventPublisher.publishEvent("Order processed: " + order.getId());
663
664
// Publish domain object as event
665
eventPublisher.publishEvent(order);
666
}
667
}
668
```
669
670
**Asynchronous Event Handling:**
671
672
```java
673
import org.springframework.scheduling.annotation.Async;
674
import org.springframework.scheduling.annotation.EnableAsync;
675
676
@Configuration
677
@EnableAsync
678
public class AsyncConfig {
679
680
@Bean
681
public Executor taskExecutor() {
682
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
683
executor.setCorePoolSize(2);
684
executor.setMaxPoolSize(10);
685
executor.setQueueCapacity(100);
686
executor.setThreadNamePrefix("event-");
687
executor.initialize();
688
return executor;
689
}
690
}
691
692
@Component
693
public class AsyncEventListener {
694
695
@Async
696
@EventListener
697
public void handleUserCreatedAsync(UserCreatedEvent event) {
698
// This will run in a separate thread
699
try {
700
Thread.sleep(2000); // Simulate slow operation
701
sendWelcomeEmail(event.getUser());
702
} catch (InterruptedException e) {
703
Thread.currentThread().interrupt();
704
}
705
}
706
707
@EventListener
708
public void handleUserCreatedSync(UserCreatedEvent event) {
709
// This runs synchronously in the main thread
710
updateUserStatistics(event.getUser());
711
}
712
}
713
```
714
715
**Generic Event Listener:**
716
717
```java
718
public class GenericEventListener implements GenericApplicationListener {
719
720
@Override
721
public boolean supportsEventType(ResolvableType eventType) {
722
return UserEvent.class.isAssignableFrom(eventType.getRawClass());
723
}
724
725
@Override
726
public boolean supportsSourceType(Class<?> sourceType) {
727
return UserService.class.isAssignableFrom(sourceType);
728
}
729
730
@Override
731
public void onApplicationEvent(ApplicationEvent event) {
732
if (event instanceof UserEvent) {
733
UserEvent userEvent = (UserEvent) event;
734
System.out.println("Handling user event: " + userEvent.getClass().getSimpleName());
735
}
736
}
737
738
@Override
739
public int getOrder() {
740
return 100; // Higher priority (lower number = higher priority)
741
}
742
743
@Override
744
public String getListenerId() {
745
return "genericUserEventListener";
746
}
747
}
748
```
749
750
**Context Event Handling:**
751
752
```java
753
@Component
754
public class ApplicationContextEventListener {
755
756
@EventListener
757
public void handleContextRefresh(ContextRefreshedEvent event) {
758
ApplicationContext context = event.getApplicationContext();
759
System.out.println("Context refreshed: " + context.getDisplayName());
760
// Initialize application-specific resources
761
}
762
763
@EventListener
764
public void handleContextStart(ContextStartedEvent event) {
765
System.out.println("Context started");
766
// Start background services
767
}
768
769
@EventListener
770
public void handleContextStop(ContextStoppedEvent event) {
771
System.out.println("Context stopped");
772
// Stop background services
773
}
774
775
@EventListener
776
public void handleContextClose(ContextClosedEvent event) {
777
System.out.println("Context closed");
778
// Cleanup resources
779
}
780
}
781
```