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