Probably the most voluminous spring source code series: events in spring

Spring implements the function of time subscription and publication, so when using spring, you no longer need to implement it yourself or use the observer mode of jdk. You can use the subscription and publication function of spring. This article will analyze the implementation of events in spring from the perspective of source code

Observer mode

public class Client {

    public static void main(String[] args) {
        // Observed (publisher)
        ISubject<String> observable = new ConcreteSubject<String>();
        // Observer (subscriber)
        IObserver<String> observer = new ConcreteObserver<String>();
        // register
        observable.attach(observer);
        // notice
        observable.notify("hello");
    }

    //Abstract observer
    public interface IObserver<E> {
        void update(E event);
    }

    //Abstract subject
    public interface ISubject<E> {
        boolean attach(IObserver<E> observer);

        boolean detach(IObserver<E> observer);

        void notify(E event);
    }

    //Specific observer
    static class ConcreteObserver<E> implements IObserver<E> {
        public void update(E event) {
            System.out.println("receive event: " + event);
        }
    }

    //Specific subject
    static class ConcreteSubject<E> implements ISubject<E> {
        private List<IObserver<E>> observers = new ArrayList<IObserver<E>>();

        public boolean attach(IObserver<E> observer) {
            return !this.observers.contains(observer) && this.observers.add(observer);
        }

        public boolean detach(IObserver<E> observer) {
            return this.observers.remove(observer);
        }

        public void notify(E event) {
            for (IObserver<E> observer : this.observers) {
                observer.update(event);
            }
        }
    }
}

The observer mode is divided into two roles, the observer and the observed. The observed object contains multiple observers. When publishing messages to the observed, the observed will facilitate all observers to notify the observer
As for the advantages, disadvantages and usage scenarios of observer mode, this paper will not describe them

JDK's own event model

jdk also implements a set of event model for us. The usage method is similar to the above, except that the above example can only publish events of string type, and jdk event model can support various types of events
First, define an event

public class Question {
    private String userName;
    private String content;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}

Observed

public class GPer extends Observable {
    private String name = "GPer Ecosphere";
    private static final GPer gper = new GPer();

    private GPer() {}

    public static GPer getInstance(){
        return gper;
    }

    public String getName() {
        return name;
    }

    public void publishQuestion(Question question){
        System.out.println(question.getUserName() + "stay" + this.name + "A question was submitted on.");
        setChanged();
        notifyObservers(question);
    }
}

Observer

public class Teacher implements Observer {

    private String name;

    public Teacher(String name) {
        this.name = name;
    }

    public void update(Observable o, Object arg) {
        GPer gper = (GPer)o;
        Question question = (Question)arg;
        System.out.println("======================");
        System.out.println(name + "Hello, teacher!\n" +
                        "You received a message from" + gper.getName() + "I hope you can answer my question. The questions are as follows:\n" +
                        question.getContent() + "\n" +
                        "Questioner:" + question.getUserName());
    }
}

client

public class Test {
    public static void main(String[] args) {
        GPer gper = GPer.getInstance();
        Teacher tom = new Teacher("Tom");
        Teacher jerry = new Teacher("Jerry");

        gper.addObserver(tom);
        gper.addObserver(jerry);

        //User behavior
        Question question = new Question();
        question.setUserName("Zhang San");
        question.setContent("What scenes does observer mode apply to?");

        gper.publishQuestion(question);
    }
}

Use of spring events

The event model in spring can directly inject the observer and the observed into the container without maintaining the relationship between the observer and the observed. Spring will automatically associate through the type of event

Defining events requires inheriting ApplicationEvent

import org.springframework.context.ApplicationEvent;
public class CustomSpringEvent extends ApplicationEvent {
   private String message;

   public CustomSpringEvent(Object source, String message) {
   	super(source);
   	this.message = message;
   }
   public String getMessage() {
   	return message;
   }
}

The observant (publisher) has a spring container implementation, which is just calling the publishing interface provided by spring

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

@Component
public class CustomSpringEventPublisher {
	@Autowired
	private ApplicationEventPublisher applicationEventPublisher;

	public void publishCustomEvent(final String message) {
		System.out.println("Publishing custom event. ");
		CustomSpringEvent customSpringEvent = new CustomSpringEvent(this, message);
		applicationEventPublisher.publishEvent(customSpringEvent);
	}
}

Observer (subscriber)

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

@Component
public class CustomSpringEventListener implements ApplicationListener<CustomSpringEvent> {
	@Override
	public void onApplicationEvent(CustomSpringEvent event) {
		System.out.println("Received spring custom event - " + event.getMessage());
	}
}

Annotation form

@Component
public class AnnotationCustomSpringEventListener  {
	@EventListener
	public void onApplicationEvent(CustomSpringEvent event) {
		System.out.println("AnnotationCustomSpringEventListener - " + event.getMessage());
	}
}

The generic injection involved here will be analyzed in a later article

Principle analysis of spring events

Today's topic is officially entered. In the previous article, we will continue to analyze the refresh() method. Next, we will come to the initapplicationeventmulticast () and registerListeners() methods

initApplicationEventMulticaster

protected void initApplicationEventMulticaster() {
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
			this.applicationEventMulticaster =
					beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
			if (logger.isTraceEnabled()) {
				logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
			}
		}
		else {
			this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
			beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
			if (logger.isTraceEnabled()) {
				logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
						"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
			}
		}
	}

An applicationeventmulticast event multicast is registered here
Equivalent to the entrance of all publishers, he can publish all events, and will find all listeners who subscribe to the event based on the type of events, and then call listener's monitoring method.
So we need to analyze applicationeventpublisher The publishevent (customspringevent) method is actually called
AnnotationConfigApplicationContext#publishEvent, we can also call this method directly

Click in


Here, the above registered multicast is obtained and handed over to the multicast for processing

Get all listener s to execute, and no more details will be described

registerListeners

protected void registerListeners() {
		// Register statically specified listeners first.
		// Give all listener s to the multicast
		for (ApplicationListener<?> listener : getApplicationListeners()) {
			getApplicationEventMulticaster().addApplicationListener(listener);
		}

		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let post-processors apply to them!
		// The listener in bdmap is handed over to the multicast
		String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
		for (String listenerBeanName : listenerBeanNames) {
			getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
		}

		// Publish early application events now that we finally have a multicaster...
		//Publishing events that already exist is empty by default
		Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
		this.earlyApplicationEvents = null;
		if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
			for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
				getApplicationEventMulticaster().multicastEvent(earlyEvent);
			}
		}
	}

This method registers some listeners and may publish some events

Keywords: Java Spring Spring Boot

Added by Ali25m on Thu, 23 Dec 2021 22:34:43 +0200