Introduction
Other URL
Event monitoring (based on SpringBoot example)_JustryDeng-CSDNblog
Brief description
The release and monitoring of events is subordinate to the observer mode; compared with MQ, the release and monitoring of events is biased towards processing certain logic "in the system".
Multiple listeners can listen to the same event. For example: if event A is released, and both listener A and listener B listen to event A, both listener A and B will process it.
Synchronous and asynchronous monitoring
Monitoring method Features When to use Synchronous monitoring The publisher thread is in the same thread as the listener thread 1. The monitoring logic is processed faster
2. It is necessary to follow the business thread according to the listener
Asynchronous monitoring The publisher thread and the listener thread are in different threads 1. Monitoring logic processing is time-consuming
2. Pursue responsiveness
priority
The order of listeners can be adjusted by implementing the Ordered interface.
Note: You must implement ApplicationListener<MyEvent>,Ordered at the same time to control the order.
The order of the following are not controllable:
- @Component+@EventListerner+实现Ordered
- Implement ApplicationListener<MyEvent>+@Order
Instance
Other URL
SpringBoot event monitoring_Chavaer-CSDN blog
SpringBoot- 4 ways to implement event monitoring_ignorewho's blog-CSDN blog_springboot event monitoring
Synchronous monitoring (unordered)
event
package com.example.event; import org.springframework.context.ApplicationEvent; public class MyEvent extends ApplicationEvent { public MyEvent(Object source) { super(source); } }
Listener
package com.example.event; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @Component public class MyListener { @EventListener public void abc(MyEvent event) { System.out.println("监听器: " + "MyListener"); System.out.println("监听器所在线程:" + Thread.currentThread().getName()); System.out.println("事件: " + event); System.out.println("事件的数据: " + event.getSource()); } }
Listener 2
package com.example.event; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @Component public class MyListener2 { @EventListener public void onApplicationEvent(MyEvent event) { System.out.println("监听器: " + "MyListener2"); System.out.println(" 所在线程: " + Thread.currentThread().getName()); System.out.println(" 事件: " + event); System.out.println(" 事件的数据:" + event.getSource()); } }
Publisher
package com.example.event; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; @Component public class MyPublisher { @Autowired ApplicationContext applicationContext; public void myPublish(String message) { System.out.println("发布器所在线程:" + Thread.currentThread().getName()); applicationContext.publishEvent(new MyEvent(message)); } }
test
Write a Controller
package com.example.controller; import com.example.event.MyPublisher; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @Autowired MyPublisher myPublisher; @GetMapping("/test1") public String test1() { myPublisher.myPublish("Hello"); return "test1 success"; } }
After starting, visit: http://localhost:8080/test1
Back-end output:
发布器所在线程:http-nio-8080-exec-1 监听器: MyListener 所在线程: http-nio-8080-exec-1 事件: com.example.event.MyEvent[source=Hello] 事件的数据:Hello 监听器: MyListener2 所在线程: http-nio-8080-exec-1 事件: com.example.event.MyEvent[source=Hello] 事件的数据:Hello
It can be found that all listeners and publishers are in the same thread.
Synchronous monitoring (ordered)
event
package com.example.event; import org.springframework.context.ApplicationEvent; public class MyEvent extends ApplicationEvent { public MyEvent(Object source) { super(source); } }
Listener
Listener 1
package com.example.event; import org.springframework.context.ApplicationListener; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; @Component public class MyListener implements ApplicationListener<MyEvent>, Ordered { @Override public void onApplicationEvent(MyEvent event) { System.out.println("监听器: " + "MyListener"); System.out.println(" 所在线程: " + Thread.currentThread().getName()); System.out.println(" 事件: " + event); System.out.println(" 事件的数据:" + event.getSource()); } @Override public int getOrder() { return 2; } }
Listener 2
package com.example.event; import org.springframework.context.ApplicationListener; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; @Component public class MyListener2 implements ApplicationListener<MyEvent>, Ordered { public void onApplicationEvent(MyEvent event) { System.out.println("监听器: " + "MyListener2"); System.out.println(" 所在线程: " + Thread.currentThread().getName()); System.out.println(" 事件: " + event); System.out.println(" 事件的数据:" + event.getSource()); } @Override public int getOrder() { return 1; } }
Publisher
package com.example.event; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; @Component public class MyPublisher { @Autowired ApplicationContext applicationContext; public void myPublish(String message) { System.out.println("发布器所在线程:" + Thread.currentThread().getName()); applicationContext.publishEvent(new MyEvent(message)); } }
test
Write a Controller
package com.example.controller; import com.example.event.MyPublisher; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @Autowired MyPublisher myPublisher; @GetMapping("/test1") public String test1() { myPublisher.myPublish("Hello"); return "test1 success"; } }
After starting, visit: http://localhost:8080/test1
Back-end output:
发布器所在线程:http-nio-8080-exec-1 监听器: MyListener2 所在线程: http-nio-8080-exec-1 事件: com.example.event.MyEvent[source=Hello] 事件的数据:Hello 监听器: MyListener 所在线程: http-nio-8080-exec-1 事件: com.example.event.MyEvent[source=Hello] 事件的数据:Hello
If the Ordered order of the implementation of the listener is reversed, the output result is as follows:
发布器所在线程:http-nio-8080-exec-1 监听器: MyListener 所在线程: http-nio-8080-exec-1 事件: com.example.event.MyEvent[source=Hello] 事件的数据:Hello 监听器: MyListener2 所在线程: http-nio-8080-exec-1 事件: com.example.event.MyEvent[source=Hello] 事件的数据:Hello
Asynchronous monitoring (unordered)
method:
- Enable asynchronous monitoring
- Add @Async to the listener (this listener must be registered by the @Component method)
event
package com.example.event; import org.springframework.context.ApplicationEvent; public class MyEvent extends ApplicationEvent { public MyEvent(Object source) { super(source); } }
Sync listener
package com.example.event; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @Component public class MyListener { @EventListener public void abc(MyEvent event) { System.out.println("监听器: " + "MyListener"); System.out.println(" 所在线程: " + Thread.currentThread().getName()); System.out.println(" 事件: " + event); System.out.println(" 事件的数据:" + event.getSource()); } }
Asynchronous listener
package com.example.event; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; @Component @Async public class MyListener2 { @EventListener public void onApplicationEvent(MyEvent event) { System.out.println("监听器: " + "MyListener2"); System.out.println(" 所在线程: " + Thread.currentThread().getName()); System.out.println(" 事件: " + event); System.out.println(" 事件的数据:" + event.getSource()); } }
Publisher
package com.example.event; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; @Component public class MyPublisher { @Autowired ApplicationContext applicationContext; public void myPublish(String message) { System.out.println("发布器所在线程:" + Thread.currentThread().getName()); applicationContext.publishEvent(new MyEvent(message)); } }
Start class
package com.example; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableAsync; @SpringBootApplication @EnableAsync public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
test
Write a Controller
package com.example.controller; import com.example.event.MyPublisher; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @Autowired MyPublisher myPublisher; @GetMapping("/test1") public String test1() { myPublisher.myPublish("Hello"); return "test1 success"; } }
After starting, visit: http://localhost:8080/test1
Back-end output:
发布器所在线程:http-nio-8080-exec-1 监听器: MyListener 所在线程: http-nio-8080-exec-1 事件: com.example.event.MyEvent[source=Hello] 事件的数据:Hello 监听器: MyListener2 所在线程: task-1 事件: com.example.event.MyEvent[source=Hello] 事件的数据:Hello
Process
Custom event
Customize events by inheriting ApplicationEvent.
The parameter of the constructor is the related data object of the event, and the listener can obtain the data object, and then perform related logic processing.
package com.example.event;
import org.springframework.context.ApplicationEvent;
public class MyEvent extends ApplicationEvent {
public MyEvent(Object source) {
super(source);
}
}
Custom listener
ApplicationListener
法1:@EventListener
Listen to a single event
package com.example.event; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; public class MyListener { @EventListener public void abc(MyEvent event) { System.out.println("监听器: " + "MyListener"); System.out.println(" 线程: " + Thread.currentThread().getName()); System.out.println(" 事件: " + event); System.out.println(" 事件的数据:" + event.getSource()); } }
or
package com.example.event; import org.springframework.context.ApplicationEvent; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; public class MyListener { @EventListener({MyEvent.class}) public void abc(ApplicationEventevent) { System.out.println("监听器: " + "MyListener"); System.out.println(" 线程: " + Thread.currentThread().getName()); System.out.println(" 事件: " + event); System.out.println(" 事件的数据: " + event.getSource()); } }
The above method is better, because there is no need for type conversion. It can be directly determined that it is of the MyEvent type.
Listen to multiple events
After the event comes in, you can use if (event instanceOf MyEvent.class) to determine what kind of event.
package com.example.event; import org.springframework.context.ApplicationEvent; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @Component public class MyListener { @EventListener({MyEvent.class, MyEvent2.class}) public void abc(ApplicationEvent event) { System.out.println("监听器: " + "MyListener"); System.out.println(" 所在线程: " + Thread.currentThread().getName()); System.out.println(" 事件: " + event); System.out.println(" 事件的数据:" + event.getSource()); } }
Listen to all ApplicationEvent
If you use this writing method, a lot of Spring's own events will be printed at startup. Any ApplicationEvent will enter here.
package com.example.event; import org.springframework.context.ApplicationEvent; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @Component public class MyListener { @EventListener public void abc(ApplicationEvent event) { System.out.println("监听器: " + "MyListener"); System.out.println(" 所在线程: " + Thread.currentThread().getName()); System.out.println(" 事件: " + event); System.out.println(" 事件的数据:" + event.getSource()); } }
Method 2: Implement ApplicationListener<T> interface
public class MyListener implements ApplicationListener<MyEvent>{ public void onApplicationEvent(MyEvent event){ System.out.println("监听器: " + "MyListener"); System.out.println(" 所在线程: " + Thread.currentThread().getName()); System.out.println(" 事件: " + event); System.out.println(" 事件的数据:" + event.getSource()); } }
SmartApplicationListener
The source code is as follows
public interface SmartApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered { boolean supportsEventType(Class<? extends ApplicationEvent> var1); default boolean supportsSourceType(@Nullable Class<?> sourceType) { return true; } default int getOrder() { return 2147483647; } }
supportsEventType: the type of event supported
supportsSourceType: the type of data supported
getOrder: 2147483641: It is 2^31-1, which is the largest positive number of a 32-bit int.
Example
event
package com.example.event; import org.springframework.context.ApplicationEvent; public class MyEvent extends ApplicationEvent { public MyEvent(Object source) { super(source); } }
Listener 1
package com.example.event; import org.springframework.context.ApplicationEvent; import org.springframework.context.event.SmartApplicationListener; import org.springframework.stereotype.Component; @Component public class MyListener implements SmartApplicationListener { @Override public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) { return aClass == MyEvent.class; } @Override public boolean supportsSourceType(Class<?> sourceType) { return sourceType == String.class; } @Override public int getOrder() { return 2; } @Override public void onApplicationEvent(ApplicationEvent event) { System.out.println("监听器: " + "MyListener"); System.out.println(" 所在线程: " + Thread.currentThread().getName()); System.out.println(" 事件: " + event); System.out.println(" 事件的数据:" + event.getSource()); System.out.println(" 是MyEvent?:" + (event instanceof MyEvent)); } }
Listener 2
package com.example.event; import org.springframework.context.ApplicationEvent; import org.springframework.context.event.SmartApplicationListener; import org.springframework.stereotype.Component; @Component public class MyListener2 implements SmartApplicationListener { @Override public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) { return aClass == MyEvent.class; } @Override public boolean supportsSourceType(Class<?> sourceType) { return sourceType == String.class; } @Override public int getOrder() { return 1; } @Override public void onApplicationEvent(ApplicationEvent event) { System.out.println("监听器: " + "MyListener2"); System.out.println(" 所在线程: " + Thread.currentThread().getName()); System.out.println(" 事件: " + event); System.out.println(" 事件的数据:" + event.getSource()); System.out.println(" 是MyEvent?:" + (event instanceof MyEvent)); } }
Publisher
package com.example.event; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; @Component public class MyPublisher { @Autowired ApplicationContext applicationContext; public void myPublish(String message) { System.out.println("发布器所在线程:" + Thread.currentThread().getName()); applicationContext.publishEvent(new MyEvent(message)); } }
test
package com.example.controller; import com.example.event.MyPublisher; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @Autowired MyPublisher myPublisher; @GetMapping("/test1") public String test1() { myPublisher.myPublish("Hello"); return "test1 success"; } }
After starting, visit: http://localhost:8080/test1
Back-end output:
发布器所在线程:http-nio-8080-exec-2 监听器: MyListener2 所在线程: http-nio-8080-exec-2 事件: com.example.event.MyEvent[source=Hello] 事件的数据:Hello 是MyEvent?:true 监听器: MyListener 所在线程: http-nio-8080-exec-2 事件: com.example.event.MyEvent[source=Hello] 事件的数据:Hello 是MyEvent?:true
If the Ordered order of the implementation of the listener is reversed, the output result is as follows:
发布器所在线程:http-nio-8080-exec-1 监听器: MyListener 所在线程: http-nio-8080-exec-1 事件: com.example.event.MyEvent[source=Hello] 事件的数据:Hello 是MyEvent?:true 监听器: MyListener2 所在线程: http-nio-8080-exec-1 事件: com.example.event.MyEvent[source=Hello] 事件的数据:Hello 是MyEvent?:true
Register the listener
the way | Scope of application | Can it be used with @Async annotations for asynchronous monitoring |
@Component | All listeners | can |
Add configuration in application.yml | Listener that implements the ApplicationListener<T> interface | Can't |
Register in the startup class | Listener that implements the ApplicationListener<T> interface | Can't |
Method 1: @Component (applicable to all listeners)
package com.example.event; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @Component public class MyListener { @EventListener public void abc(MyEvent event) { System.out.println("监听器:" + "MyListener"); System.out.println("线程:" + Thread.currentThread().getName()); System.out.println("事件:" + event); System.out.println("事件的数据:" + event.getSource()); } }
package com.example.event; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; @Component public class MyListener2 implements ApplicationListener<MyEvent> { @Override public void onApplicationEvent(MyEvent event) { System.out.println("监听器:" + "MyListener2"); System.out.println("线程:" + Thread.currentThread().getName()); System.out.println("事件:" + event); System.out.println("事件的数据:" + event.getSource()); } }
Method 2: Add configuration to application.yml (only applicable to listeners that implement the ApplicationListener<T> interface)
context: listener: classes: com.example.event.MyListener,com.example.event.MyListener2
Method 3: Register in the startup class (only applicable to listeners that implement the ApplicationListener<T> interface)
package com.example; import com.example.event.MyListener; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { // 原来是这样的:SpringApplication.run(DemoApplication.class, args); ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args); context.addApplicationListener(new MyListener()); } }
Post an event
Method 1: Inject ApplicationContext and call its publishEvent method
package com.example.event; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; @Component public class MyPublisher { @Autowired ApplicationContext applicationContext; public void myPublish(String message) { applicationContext.publishEvent(new MyEvent(message)); } }
Method 2: Release in the startup class
package com.example; import com.example.event.MyEvent; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { //原来是:SpringApplication.run(DemoApplication.class, args); ConfigurableApplicationContext context =SpringApplication.run(DemoApplication.class, args); context.publishEvent(new MyEvent("Hello")); } }
SpringBoot startup event
Other URL
Start events (in chronological order)
1、ApplicationStartingEvent
This event is sent when the Spring Boot application starts and before any processing (except for the registration of listeners and initializers).
2、ApplicationEnvironmentPreparedEvent
This event is sent before the Spring context is created when it is known to use the Spring Environment in the context.
3、ApplicationContextInitializedEvent
This event is sent when the Spring application context (ApplicationContext) is ready and the application initializers (ApplicationContextInitializers) have been called, before the bean definitions are loaded.
4、ApplicationPreparedEvent
This event is sent before the Spring context is refreshed and after the bean definitions are loaded.
5、ApplicationStartedEvent
This event is sent after the Spring context is refreshed and before the application/command-line runners are invoked.
6、AvailabilityChangeEvent
This event is sent immediately after the last event, the state: ReadinessState.CORRECT, which means that the application is already active.
7、ApplicationReadyEvent
This event is sent after any application/command-line runners are called.
8、AvailabilityChangeEvent
This event is sent immediately after the last event, the state: ReadinessState.ACCEPTING_TRAFFIC, indicating that the application is ready to receive requests.
9、ApplicationFailedEvent
This event is sent when the application starts abnormally.
The event list described above only includes SpringApplicationEvents events bound to SpringApplication. In addition to these events, the following events will also be sent after ApplicationPreparedEvent and before ApplicationStartedEvent:
WebServerInitializedEvent
This Web server initialization event is sent after the WebServer starts, and corresponds to ServletWebServerInitializedEvent (Servlet Web server initialization event) and ReactiveWebServerInitializedEvent (Responsive Web server initialization event).
ContextRefreshedEvent
This context refresh event is sent after the Spring application context (ApplicationContext) is refreshed.
principle
Other URL
In- depth understanding of the Spring/SpringBoot event monitoring mechanism-Knowing the
Springboot event mechanism to integrate the EventBus application (event-driven model)_fw19940314的博客-CSDN blog
Source code analysis
myPublisher.myPublish("Hello") //HelloController
applicationContext.publishEvent(new MyEvent(message)); //MyPublisher
publishEvent(event, (ResolvableType)null); //AbstractApplicationContext.class
// AbstractApplicationContext
getApplicationEventMulticaster().multicastEvent((ApplicationEvent)applicationEvent, eventType);
// AbstractApplicationContext
applicationEventMulticaster.multicastEvent((ApplicationEvent)applicationEvent, eventType)
SimpleApplicationEventMulticaster#multicastEvent
以下都在SimpleApplicationEventMulticaster
multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType)
// 此时,type为:com.example.tmp.MyEvent
ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
for (ApplicationListener<?> listener : getApplicationListeners(event, type))
invokeListener(listener, event)
AbstractApplicationEventMulticaster#getApplicationListeners
getApplicationListeners(event, type))
retriever = new ListenerRetriever(true);
Collection<ApplicationListener<?>> listeners = retrieveApplicationListeners(eventType, sourceType, retriever);
listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
遍历listeners,如果监听器支持此事件,则加入集合并返回。