Detailed explanation of ApplicationListener and ContextRefreshedEvent in Spring

 

Reprinted from: https://www.xttblog.com/?p=2053

 

The event mechanism, as a programming mechanism, is supported in many languages. The JAVA language is no exception. The participants of the event mechanism in java have three roles:

  1. event object
  2. event source
  3. event listener

The meaning of these three roles is easy to understand literally, and they define a basic model of the event mechanism. As a common programming design mechanism, the event mechanism is used in the design of many open source frameworks. SpringFramework is no exception.

During the startup process of the IOC container, when all the beans have been processed, the spring IOC  container will have an action of publishing events. It can be seen from the source code of AbstractApplicationContext:

1
2
3
4
5
6
7
8
9
10
11
protected void finishRefresh() {
     // Initialize lifecycle processor for this context.
     initLifecycleProcessor();
     // Propagate refresh to lifecycle processor first.
     getLifecycleProcessor().onRefresh();
     // Publish the final event.
     publishEvent( new ContextRefreshedEvent( this ));
     // 业余草:www.xttblog.com
     // Participate in LiveBeansView MBean, if active.
     LiveBeansView.registerApplicationContext( this );
}

In this way, when the ioc container has loaded and processed the corresponding bean, it also provides us with an opportunity (InitializingBean first, then ApplicationListener<ContextRefreshedEvent>) to do what we want to do. In fact, this is an extension provided by the spring ioc container. We can use this extension mechanism like this.

1
2
org.springframework.context.ApplicationEvent
org.springframework.context.ApplicationListener

One of the easiest ways is to let our bean implement the ApplicationListener interface, so that when an event is published, the spring 's ioc container will use the container's instance object as the event source class, and find the event listener from it. At this time, the ApplicationListener interface instance The onApplicationEvent(E event) method in will be called, and our logic code will be written here. Thus our purpose is achieved. But this also brings a thought. Some people may think that such code can also be implemented by implementing spring 's InitializingBean interface, and it will also be automatically invoked by the spring container, but everyone should think that if we want to do things now , it is necessary to wait until all beans have been processed before proceeding. At this time, the implementation of the InitializingBean interface is not suitable, so it is necessary to deeply understand the application of the event mechanism.

A colleague once used ApplicationListener to repeatedly load the xml configuration file several times. So basic knowledge must be mastered.

Here is a complete example:

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
31
32
33
34
35
36
public class ApplicationContextListener  implements ApplicationListener<ContextRefreshedEvent> {
     private static Logger _log = LoggerFactory.getLogger(ApplicationContextListener. class );
     @Override
     public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
         // root application context
         if ( null == contextRefreshedEvent.getApplicationContext().getParent()) {
             _log.debug( ">>>>> spring初始化完毕 <<<<<" );
             // spring初始化完毕后,通过反射调用所有使用BaseService注解的initMapper方法
             Map<String, Object> baseServices =
             contextRefreshedEvent.getApplicationContext().getBeansWithAnnotation(BaseService. class );
             for (Object service : baseServices.values()) {
                 _log.debug( ">>>>> {}.initMapper()" , service.getClass().getName());
                 try {
                     Method initMapper = service.getClass().getMethod( "initMapper" );
                     initMapper.invoke(service);
                 catch (Exception e) {
                     _log.error( "初始化BaseService的initMapper方法异常" , e);
                     e.printStackTrace();
                 }
             }
             // 系统入口初始化,业余草:www.xttblog.com
             Map<String, BaseInterface> baseInterfaceBeans =
             contextRefreshedEvent.getApplicationContext().getBeansOfType(BaseInterface. class );
             for (Object service : baseInterfaceBeans.values()) {
                 _log.debug( ">>>>> {}.init()" , service.getClass().getName());
                 try {
                     Method init = service.getClass().getMethod( "init" );
                     init.invoke(service);
                 catch (Exception e) {
                     _log.error( "初始化BaseInterface的init方法异常" , e);
                     e.printStackTrace();
                 }
             }
         }
     }
}

The above is the related usage of ApplicationListener and ContextRefreshedEvent.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326035288&siteId=291194637