ApplicationEvent
as well as Listener
yes Spring An event monitor provided for us 、 Implementation of subscription , The internal implementation principle is the observer design pattern , The original intention is to decouple the business logic of the system , Improve scalability and maintainability .
adopt ApplicationEvent Classes and ApplicationListener Interface to be provided in ApplicationContext Processing events in . If one bean Realization ApplicationListener, So every time ApplicationEvent Published to ApplicationContext On , that bean Will be informed .
Spring The following standard events are provided :
Serial number | Spring Built in events & describe |
---|---|
1 | ContextRefreshedEvent ApplicationContext When initialized or refreshed , The incident was released . It can also be found in ConfigurableApplicationContext Used in the interface refresh() Method to happen . |
2 | ContextStartedEvent When using ConfigurableApplicationContext Interface start() Method start up ApplicationContext when , The incident was released . You can investigate your database , Or you can restart any stopped application after receiving this event . |
3 | ContextStoppedEvent When using ConfigurableApplicationContext Interface stop() Method stop ApplicationContext when , Publish this event . You can do the necessary cleanup work after receiving this incident . |
4 | ContextClosedEvent When using ConfigurableApplicationContext Interface close() Method shut down ApplicationContext when , The incident was released . A closed context reaches the end of the lifecycle ; It can’t be refreshed or restarted . |
5 | RequestHandledEvent This is a web-specific event , Tell all bean HTTP The request has been served . |
Let’s use an example to illustrate :
The overall structure of the project is shown in the figure below
image.png
1、 Build the project
<groupId>com.br</groupId>
<artifactId>ListenerDemo</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.16</version>
</dependency>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2、 establish Event event
First of all :listener It’s all about event To hang up .
package com.br.event;
import com.br.bean.User;
import org.springframework.context.ApplicationEvent;
/**
* @author jackcooper
* @create 2018-02-27 13:54
*/
public class UserRegisterEvent extends ApplicationEvent {
public User user;
/**
*
* @param source The object of the incident
* @param user Register user objects
*/
public UserRegisterEvent(Object source,User user) {
super(source);
this.user = user;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
3、 Event publishing
This part is mainly triggered in the business logic module , Mainly used ApplicationContext Class and its publishEvent(ApplicationEvent t) Method .
package com.br.service;
import com.br.bean.User;
import com.br.event.UserRegisterEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
/**
* @author jackcooper
* @create 2018-02-27 14:03
*/
@Service
public class UserService {
@Autowired
private ApplicationContext applicationContext;
public void register(User user){
// Omit business logic
//....
// Release UserRegisterEvent event
applicationContext.publishEvent(new UserRegisterEvent(this,user));
}
}
4、 establish Event Event monitoring
The first way : be based on EventListener Annotation implementation
The way of annotation is relatively simple , You don’t need to implement any interfaces
package com.br.listener;
import com.br.bean.User;
import com.br.event.UserRegisterEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
/**
* @author jackcooper
* @create 2018-02-27 14:17
* @deprecated Method 1 : The way of annotation is relatively simple , You don't need to implement any interfaces The order is random
*/
@Component
public class AnnotationRegisterListener {
/**
* Register and monitor the implementation method
* @param userRegisterEvent User registration event
*/
@EventListener
public void sendEmail(UserRegisterEvent userRegisterEvent)
{
// Get registered user object
User user = userRegisterEvent.getUser();
//todo
// Output registered user information
System.out.println(" Send E-mail , user name :"+user.getName()+", mailbox :"+user.getEmail());
}
/**
* Register and monitor the implementation method
* @param userRegisterEvent User registration event
*/
@EventListener
public void register(UserRegisterEvent userRegisterEvent)
{
// Get registered user object
User user = userRegisterEvent.getUser();
//todo
// Output registered user information
System.out.println("1 Registration information , user name :"+user.getName()+", mailbox :"+user.getEmail());
}
}
The second way : Realization ApplicationListener Interface
The same way Spring The most common way to monitor events before , In the realization of ApplicationListener Interface needs to pass listening events as generics
package com.br.listener;
import com.br.bean.User;
import com.br.event.UserRegisterEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
/**
* @author jackcooper
* @create 2018-02-27 14:29
* @deprecated ApplicationListener Implement monitoring : The same way Spring The most common way to monitor events before , In the realization of ApplicationListener Interface needs to pass listening events as generics , The listening implementation code is as follows
*/
@Component
public class RegisterListener implements ApplicationListener<UserRegisterEvent> {
/**
* Implement monitoring
* @param userRegisterEvent
*/
@Override
public void onApplicationEvent(UserRegisterEvent userRegisterEvent) {
// Get registered user object
User user = userRegisterEvent.getUser();
//../ Ellipsis logic
// Output registered user information
System.out.println("2 Registration information , user name :"+user.getName()+", password :"+user.getEmail());
}
}
The third way : Realization SmartApplicationListener Interface
package com.br.listener;
import com.br.bean.User;
import com.br.event.UserRegisterEvent;
import com.br.service.UserService;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.stereotype.Component;
/**
* @author 10400
* @create 2018-02-27 15:03
* @deprecated Orderly monitoring
*/
@Component
public class SmartRegisterListener implements SmartApplicationListener {
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
// Only UserRegisterEvent The following logic is executed by the listening type
return aClass == UserRegisterEvent.class;
}
@Override
public boolean supportsSourceType(Class<?> aClass) {
// Only in UserService Issued within UserRegisterEvent The following logic will only be executed during the event
return aClass == UserService.class;
}
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
// Convert event types
UserRegisterEvent userRegisterEvent = (UserRegisterEvent) applicationEvent;
// Get registered user object information
User user = userRegisterEvent.getUser();
//.../ Complete the registration business logic
System.out.println("SmartRegisterListener" + user.getName());
}
/**
* return The lower the value of the, the higher the priority , The higher the order of execution .
* @return
*/
@Override
public int getOrder() {
return 10;
}
}
SmartApplicationListener Interface inherits global listening ApplicationListener, And generic objects use ApplicationEvent As a global monitor , Can be understood as using SmartApplicationListener As the implementation of listening parent interface , Listen to all event releases .
You can see that in addition to the above methods , One is also provided getOrder Method , This method can solve the problem of the order in which listening is performed ,return The lower the value of the, the higher the priority , The higher the order of execution .
The fourth way : Use @Async Implement asynchronous listening
@Aysnc It’s actually Spring A component inside , It can realize asynchronous call to single or multiple methods in the class , This can greatly save the waiting time . The internal implementation mechanism is thread pool task ThreadPoolTaskExecutor, Through the thread pool to configure @Async Methods or classes that perform actions .
- Thread task pool configuration
We create a ListenerAsyncConfiguration, And use @EnableAsync Annotation enable supports asynchronous processing , The specific code is as follows :
@Configuration
@EnableAsync
public class ListenerAsyncConfiguration implements AsyncConfigurer
{
/**
* Get asynchronous thread pool execution object
* @return
*/
@Override
public Executor getAsyncExecutor() {
// Use Spring Built in thread pool task object
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
// Set thread pool parameters
taskExecutor.setCorePoolSize(5);
taskExecutor.setMaxPoolSize(10);
taskExecutor.setQueueCapacity(25);
taskExecutor.initialize();
return taskExecutor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return null;
}
}
Our custom listening asynchronous configuration class implements AsyncConfigurer Interface and implementation getAsyncExecutor Method to provide access to the thread task pool object .
We just need to add… To the asynchronous method @Async Annotation can realize asynchronous call of method , To prove it , We’re sending emails onApplicationEvent Method to add thread blocking 3 second , The modified code is as follows :
/**
* supportsEventType & supportsSourceType Two methods return true Call this method to execute the business logic
* @param applicationEvent Specific monitoring examples , Here is UserRegisterEvent
*/
@Override
@Async
public void onApplicationEvent(ApplicationEvent applicationEvent) {
try {
Thread.sleep(3000);// Sleeping quietly 3 Second
}catch (Exception e)
{
e.printStackTrace();
}
// Convert event types
UserRegisterEvent userRegisterEvent = (UserRegisterEvent) applicationEvent;
// Get registered user object information
UserBean user = userRegisterEvent.getUser();
System.out.println(" user :"+user.getName()+", Registered successfully , Send email notification .");
}
Article reference
https://www.jianshu.com/p/4359dd4b36a6