What is ApplicationEventPublisher?

  • As implementation of Observer pattern, provide interface for event programming.

1. Make Event

Event Publisher consist of occur part and receive part and Object to be used for delivery.

First, occur part.

To occur EventPublisher, should use ApplicationEventPublisher object, ApplicationContext has ApplicationEventPublisher object already.

And use publichEvent method with Object to be used for delivery inside.

1
2
3
4
5
6
7
8
9
10
11
@Component
public class EventRunner implements ApplicationRunner {

@Autowired
ApplicationEventPublisher eventPublisher;

@Override
public void run(ApplicationArguments args) throws Exception {
eventPublisher.publishEvent(new MyEvent(this, 100));
}
}

Second, The Object to be used for delivery like below code.

In constructor, meaning of source is for can tracking what object occurred.

1
2
3
4
5
6
7
8
9
10
11
12
public class MyEvent {

private int data;

public MyEvent(Object source, int data){
this.data = data;
}

public int getData(){
return data;
}
}

Third, receive part like below code.

Need to write @Component for register bean and a @EventListener on the method want to receive.

1
2
3
4
5
6
7
8
@Component
public class MyEventHandler {

@EventListener
public void onApplicationEvent(MyEvent myEvent) {
System.out.println("Event occurred -> " + myEvent.getData());
}
}

Then the result like below.

1
Event occurred -> 100

2. Handle event

If there are over 2 receive handler, what is order?

Create another handler for test.

1
2
3
4
5
6
7
8
@Component
public class AnotherHandler {

@EventListener
public void handle(MyEvent myEvent){
System.out.println("Another -> "+myEvent.getData());
}
}

Then result is like below.

1
2
Event occurred -> 100
Another -> 100

If want to give order at each receiver, can write ‘@Order(Ordered.HIGHEST_PRECEDENCE)’.

1
2
3
4
5
6
7
8
9
@Component
public class AnotherHandler {

@EventListener
@Order(Ordered.HIGHEST_PRECEDENCE)
public void handle(MyEvent myEvent){
System.out.println("Another -> "+myEvent.getData());
}
}

Then the result like below.

1
2
Another -> 100
Event occurred -> 100

When use to thread, need write @Async.

1
2
3
4
5
6
7
8
9
10
@Component
public class AnotherHandler {

@EventListener
@Async
public void handle(MyEvent myEvent){
System.out.println("Current Thread -> " + Thread.currentThread().toString());
System.out.println("Another -> "+myEvent.getData());
}
}

And need write @EnableAsync in Application.java

1
2
3
4
5
6
7
8
@SpringBootApplication
@EnableAsync // Enable async
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

Events provided by spring.

  • ContextRefreshedEvent : Occurs when create or refresh ApplicationContext.

  • ContextStartedEvent : Occurs when receive signal to start() ApplicationContext.

  • ContextStoppedEvent : Occurs when receive signal to stop() ApplicationContext.

  • ContextClosedEvent : Occurs when remove singleton bean to close() ApplicationContext.

  • RequestHandledEvent : Occurs when request HTTP.

Code structure like below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Component
public class EventRunner implements ApplicationRunner {

@Autowired
ApplicationEventPublisher eventPublisher;

@Override
public void run(ApplicationArguments args) throws Exception {
eventPublisher.publishEvent(new MyEvent(this, 100));

((ConfigurableApplicationContext)eventPublisher).start();
((ConfigurableApplicationContext)eventPublisher).stop();
((ConfigurableApplicationContext)eventPublisher).close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Component
public class AnotherHandler {

@EventListener
@Async
public void handle(MyEvent myEvent){
System.out.println("Current Thread -> " + Thread.currentThread().toString());
System.out.println("Another -> "+myEvent.getData());
}

@EventListener
public void handle(ContextRefreshedEvent event){
System.out.println("Refresh");
}

@EventListener
public void handle(ContextStartedEvent event){
System.out.println("Start");
}

@EventListener
public void handle(ContextStoppedEvent event){
System.out.println("Stop");
}

@EventListener
public void handle(ContextClosedEvent event){
System.out.println("Close");
}
}

The result like this.

1
2
3
4
5
6
7
8
9
10
11
Refresh
2020-02-05 00:07:51.660 INFO 2848 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2020-02-05 00:07:51.663 INFO 2848 --- [ main] com.example.demo.Application : Started Application in 2.354 seconds (JVM running for 3.252)
class com.example.demo.eventPublisher.EventRunner
Current Thread -> Thread[main,5,main]
Event occurred -> 100
Current Thread -> Thread[task-2,5,main]
Another -> 100
Start
Stop
Close