【Spring】Start from Spring source code to analyze broadcasting and monitoring and complete project combat

The recent epidemic situation is severe, and the situation is not optimistic. I dare not go out on weekends, and hide at home "Ge You Lie". Having nothing to do, I went through Springthe source code again. I don’t know if I don’t look through it, but I’m startled when I turn it over. The source code I turned over before has already been eaten into my stomach. Goodbye is also a stranger.

Personal suggestion: In order to quickly pick up a certain knowledge point in the future, the best way is to form a document. When there is an omission next time, read the document directly, and go through it according to the previous thinking, "clean and hygienic".

In the previous article, we have introduced how to quickly get started with the "event notification mechanism" in the project, I believe everyone has mastered it. javaerBut as seniors , we need to know what it is, and even more so, why it is. Today, I will take you to analyze the underlying implementation principles of broadcasting and monitoring from the perspective of source code.

The source code import tutorial is also prepared for you, don't you want to try it?

Version number: spring-framework-5.0.x

Source code analysis

In order to realize the functions of broadcasting and monitoring, Springwe provide us with two important functional interfaces: ApplicationEventPublisherand ApplicationListener. The former publishEvent()method provides us with the ability to send broadcasts; the latter onApplicationEvent()method provides us with the ability to listen to and process events.

Next, let's analyze springhow to use these two abilities.

I wonder if you are familiar with the initialization call process of the singleton object? The main calling method flow is as follows:

send broadcast

applyBeanPostProcessorsBeforeInitializationThe method will traverse all Beanthe post-processors created by the factory, and then execute postProcessBeforeInitializationthe methods corresponding to the post-processors in sequence.

In the implementation class of this method, we see two familiar class names

I don’t know if you still remember, these two classes are two post-processors beanFactoryadded during the preparation process , so this place will execute the implementation methods in these two classes in turn.bean

Since the implementation method of the class in the blue box is given by the default implementation and returned as it is bean, there is no need to analyze too much here. Let's focus on the method implementation of the class in the red box .

The most important thing in this method is invokeAwareInterfacesthe method. Its function is to detect beanwhether the corresponding interface has been implemented Aware, and if it is implemented, it will make related calls.

if (bean instanceof ApplicationEventPublisherAware) {
    
    
    ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}

We found that invokeAwareInterfacesthe above code appeared in the method, isn't this related to broadcast sending? So as long as we write a class to implement ApplicationEventPublisherAwarethe interface, we can beaninject an ApplicationEventPublisherobject into it and gain the ability to send broadcasts.

listen for messages

applyBeanPostProcessorsAfterInitializationThe method will also traverse all Beanthe post-processors created by the factory, and then execute postProcessAfterInitializationthe methods corresponding to the post-processors in sequence.

Similarly, there are also two classes in the implementation class of this method ApplicationContextAwareProcessor, ApplicationListenerDetectorbut the difference is that the implementation method of the former class is given by the default implementation returned as it is bean, while the latter has done related processing.

this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);

The above code is to add ApplicationListenerthe ones that implement the interface beanto the list of listeners, and finally save them in the collection of AbstractApplicationEventMulticastermember variables .defaultRetrieverapplicationListeners

Guess: When sending a broadcast message, find these listeners in the collection directly, and then call the method of each listener onApplicationEventto complete the event processing.

case analysis

In refresh()the finishRefresh()method,

publishEvent(new ContextRefreshedEvent(this));

Send a ContextRefreshedEventbroadcast message of event type to represent Springthe end of container initialization. Through analysis, it is found that the most important part of this method is the following code:

//真正的广播交给 applicationEventMulticaster 来完成
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);

refresh()will initApplicationEventMulticaster()be applicationEventMulticasterinitialized asSimpleApplicationEventMulticaster

In the method of the implementation class SimpleApplicationEventMulticaster, the registered ApplicationListenerlist will be found, and then invokeListenerthe methods will be called respectively (the process of passing the listener and event as parameters to the method and executing it is the process of sending the broadcast).

The bottom layer calls listener.onApplicationEvent(event);methods, that is, the logic for each listener implementation class to process broadcast messages independently.

Binding of messages and listeners

Seeing this, have you already discovered that the binding of the message type and the listener occurs during the broadcasting process. Next let's find out

Let's look at the method multicastEvent()in the method getApplicationListeners(event, type).

In this method, ConcurrentHashMapthe type cache is used, so each type of event will trigger a binding operation retrieverCachewhen it is broadcast . Its key is determined by the source and type of the event, and its value contains all listener lists determined by the source and type of the event.

The binding logic appears in retrieveApplicationListenersthe method, and you can check it in the source code.

Practical teaching

What is achieved on paper is always shallow, and I know that this matter must be done. In order to better understand the process of broadcasting and monitoring, of course we have to use actual combat to assist!

custom event

public class MyEvent extends ApplicationContextEvent {
    
    
    public MyEvent(ApplicationContext source) {
    
    
        super(source);
    }
}

custom radio

@Component
public class MyPublisher implements ApplicationEventPublisherAware, ApplicationContextAware {
    
    

	private ApplicationEventPublisher applicationEventPublisher;

	private ApplicationContext applicationContext;

	@Override
	public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
    
    
		this.applicationEventPublisher = applicationEventPublisher;
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    
    
		this.applicationContext = applicationContext;
	}

	//发送广播消息
	public void publishEvent(){
    
    
		System.out.println("我要开始发送消息了。。。");
		MyEvent myEvent = new MyEvent(applicationContext);
		applicationEventPublisher.publishEvent(myEvent);
	}
}

MyPublisherWhen the interface is implemented ApplicationEventPublisherAware, the method will be called back during springinitialization (see above invokeAwareInterfaces) , and when the initialization (adding post-processor ) setApplicationEventPublisheris obtained , it is indirectly implemented to obtain the sending ability. What is actually executed is the method in the class .beanApplicationContextAwareProcessorAbstractApplicationContextAbstractApplicationContextApplicationEventPublisherAbstractApplicationContextpublishEvent

custom monitoring

@Component
public class MyEventListener implements ApplicationListener<MyEvent> {
    
    

    @Override
    public void onApplicationEvent(MyEvent event) {
    
    
        System.out.println("我监听到你的消息了");
    }
}

MyEventListenerThe interface is implemented ApplicationListener, it will be added to it when springit is initialized (see above addApplicationListener) applicationListeners, and publishEventit will be executed when the method MyEventListeneris executed onApplicationEvent.

client

@RestController
@RequestMapping("/demo")
public class DemoTest {
    
    

    @Autowired
    private MyPublisher myPublisher;

    @RequestMapping("/test")
    public void test() {
    
    
        myPublisher.publishEvent();
    }
}

The broadcast can be sent after accessing 127.0.0.1:8008/demo/test, and the content of sending and monitoring is as follows:

我要开始发送消息了。。。
我监听到你的消息了

Seeing this, I believe you have fully grasped the essence of broadcasting and monitoring, so hurry up and practice it.

After reading the article, and looking at my hair that has become thinner and thinner for writing this article, I couldn't help crying. Maybe only by giving me likes can calm my mood.

Good-looking skins are the same, interesting souls are one in a million, let us warm each other in this cold city, I am Ah Q, see you in the next issue!

Guess you like

Origin blog.csdn.net/Qingai521/article/details/131548884