Tauchen Sie beim Debuggen des Quellcodes in den Spring-Event-Mechanismus ein und imitieren Sie das Spring-Event-Listening-Skelett basierend auf dem Beobachtermuster

1.Testfälle

ein Ereignis definieren

package com.example.demo.event;
import org.springframework.context.ApplicationEvent;

public class MyEvent extends ApplicationEvent {
    
    
    public MyEvent(Object source) {
    
    
        super(source);
    }
}

Definieren Sie zwei Zuhörer

package com.example.demo.event;

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class Listener1 implements ApplicationListener<MyEvent> {
    
    
    @Override
    public void onApplicationEvent(MyEvent event) {
    
    
        String source = (String) event.getSource();
        System.out.println(this.getClass().getName() + ":" + source);
    }
}
package com.example.demo.event;

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class Listener2 implements ApplicationListener<MyEvent> {
    
    
    @Override
    public void onApplicationEvent(MyEvent event) {
    
    
        String source = (String) event.getSource();
        System.out.println(this.getClass().getName() + ":" + source);
    }
}

Fügen Sie das ApplicationEventPublisher-Objekt in den Spring-Container ein und veröffentlichen Sie das Ereignis

package com.example.demo;


import com.example.demo.event.MyEvent;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

@RunWith(SpringRunner.class)
@SpringBootTest
public class EventPublisherTest {
    
    

    @Resource
    private ApplicationEventPublisher eventPublisher;

    @Test
    public void test() {
    
    
        eventPublisher.publishEvent(new MyEvent("xxx"));
    }
}

2. DEBUG-Quellcode-Analyse

Es ist leicht zu findeneventPublisher.publishEvent(new MyEvent("xxx"));. Sie können feststellen, dassSimpleApplicationEventMulticaster, das Event-Publishing-Objekt, alle Listener-Objekte und MyEvent-Objekte enthält a> Methode
Der Ereignisveröffentlichungsprozess besteht eigentlich darin, jedes Listener-Objekt zu durchlaufen und seine eigene ,onApplicationEvent()

Hauptmethode der SimpleApplicationEventMulticaster-Klasse:

  • addApplicationListener(ApplicationListener<?> listener) :
  • addApplicationListenerBean(String listenerBeanName):
  • removeApplicationListener(ApplicationListener<?> listener):
  • removeApplicationListenerBean(String listenerBeanName):
  • multicastEvent(ApplicationEvent-Ereignis): Broadcast-Ereignis;
  • multicastEvent(ApplicationEvent event, @Nullable
    ResolvableType eventType): Broadcast-Ereignis, geben Sie den Quelltyp des Ereignisses an.

Fügen Sie hier eine Bildbeschreibung ein

3. Asynchrone Überwachung

Am Haltepunkt in der obigen Abbildung können Sie erkennen, dass das ApplicationEventMulticaster-Objekt das taskExecutor-Feld auf Null hält, was dazu führt, dass nicht alle Listener asynchron ausgeführt werden. Hier müssen Sie eine Möglichkeit finden, den Thread-Pool in diesem Feld festzulegen:
Springboot konfiguriert standardmäßig ein ThreadPoolTaskExecutor-Objekt im Container. Hier können Sie es herausnehmen und auf das ApplicationEventMulticaster-Objekt setzen

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;


/**
 * @author Administrator
 */
@SpringBootApplication
public class DemoApplication {
    
    

    @Resource
    private SimpleApplicationEventMulticaster eventMulticaster;
    @Resource
    private ThreadPoolTaskExecutor executor;

    @PostConstruct
    public void setEventExecutor() {
    
    
        eventMulticaster.setTaskExecutor(executor);
    }

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

4.ApplicationListener-Unterschnittstelle

Sie können auch die getOrder-Methode der Unterklasse implementieren, um eine Mehrfach-Listener-Sortierung zu implementieren. Implementieren Sie „supportsEventType“ und „supportsSourceType“, um eine Filterung nach Klasse oder nach der Klasse der Ereignisquelle Source zu implementieren
Fügen Sie hier eine Bildbeschreibung ein

5. Unterstützung für Anmerkungen

Hier wird die Überwachung nicht durch die Implementierung von Schnittstellen implementiert, sondern sequentiell sortiert, die Überwachung nach Ereignistyp gefiltert und mit bequemeren Anmerkungen implementiert, und mehrere Überwachungen können in einer Klasse implementiert werden.

package com.example.demo.event;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
public class Listener3 {
    
    

    @Order(Integer.MIN_VALUE) // 优先级最高
    @EventListener(MyEvent.class)  // 只监听指定类型的事件
    public void onApplicationEvent(ApplicationEvent event) {
    
    
        MyEvent myEvent = (MyEvent) event;
        System.out.println(this.getClass().getName() + ":" + myEvent.getSource());
    }
}

6. Hohe Nachahmung der Frühlingsereignisüberwachung basierend auf dem Beobachtermuster

6.1 Definieren Sie zunächst ein benutzerdefiniertes Ereignis

Beobachtermusterereignisse und Listener-Schnittstellen der obersten Ebene wurden in Java definiert

package com.example.demo.javanativeevent;

import java.util.EventObject;

public class MyJavaNativeEvent extends EventObject {
    
    

    public MyJavaNativeEvent(Object source) {
    
    
        super(source);
    }
}

6.2 Definieren Sie zwei Listener

Da der von Java bereitgestellte EventListener keine spezifische Abhörmethode und keine geeignete Unterschnittstelle hat, wird hier eine Unterschnittstelle ähnlich wie spirng angepasstNativeEventListener. Auf diese Weise besteht die nachfolgende Ereignisveröffentlichung darin, diese Art von Schnittstelle zu durchlaufen und die Methode onApplicationEvent() aufzurufen

package com.example.demo.javanativeevent;

import java.util.EventListener;
import java.util.EventObject;

public interface NativeEventListener extends EventListener {
    
    
    void onApplicationEvent(EventObject event);
}
package com.example.demo.javanativeevent;

import java.util.EventObject;


public class JavaNativeListener1 implements NativeEventListener {
    
    

    @Override
    public void onApplicationEvent(EventObject event){
    
    
        String source = (String)event.getSource();
        System.out.println(this.getClass().getName()+":"+source);
    }
}

6.3 Definieren Sie ein Objekt, das alle Zuhörer enthält, ähnlich wie bei SpringSimpleApplicationEventMulticaster

package com.example.demo.javanativeevent;

import java.util.ArrayList;
import java.util.Collections;
import java.util.EventObject;
import java.util.List;

/**
 * TODO
 *
 * @author majun
 * @version 1.0
 * @since 2023-08-13 18:50
 */
public class SimpleJavaNativeEventMulticaster {
    
    

    public List<NativeEventListener> eventListeners= Collections.synchronizedList(new ArrayList<>(8));


    public void addListener(NativeEventListener listener){
    
    
        this.eventListeners.add(listener);
    }
    public void multicastEvent(EventObject eventObject){
    
    
        eventListeners.stream().parallel().forEach(listener -> {
    
    
           listener.onApplicationEvent(eventObject);
        });
    }
}

6.4 Event-Release-Test

package com.example.demo.javanativeevent;

/**
 * TODO
 *
 * @author majun
 * @version 1.0
 * @since 2023-08-13 19:01
 */
public class EventPublishTest {
    
    


    public static void main(String[] args) {
    
    
        // 注册两个listener,这是spirng把这个过程隐藏在spring容器初始化过程中了
        SimpleJavaNativeEventMulticaster eventMulticaster = new SimpleJavaNativeEventMulticaster();
        eventMulticaster.addListener(new JavaNativeListener1());
        eventMulticaster.addListener(new JavaNativeListener2());
        // 发布事件
        eventMulticaster.multicastEvent(new MyJavaNativeEvent("yyyy"));
    }
}

おすすめ

転載: blog.csdn.net/qq_39506978/article/details/132261572