or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

annotation-configuration.mdapplication-context.mdcaching.mdconfiguration-properties.mddependency-injection.mdevent-handling.mdformatting.mdindex.mdlifecycle-management.mdscheduling.mdvalidation.md

event-handling.mddocs/

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

```