What is the observer model

The observer pattern defines a one-to-many dependency that allows multiple observer objects to listen on a subject object simultaneously. When the state of the topic object changes, all observers are notified so that they can update themselves.

The role of the observer model

The main thing is decoupling. Make both sides of coupling dependent on abstraction, not concrete (abstract coupling). So that each change does not affect the other (depending on the inversion principle). And set up a trigger mechanism.

Three, four roles in Spring

1. ApplicationEvent

ApplicationEvent is the parent class of all event objects. ApplicationEvent inherits from EventObject in the JDK. All events need to inherit ApplicationEvent and get the event source from source.

2. ApplicationListener

ApplicationListener An event listener, also known as an observer. Inheriting from EventListener in the JDK, there is only one method onApplicationEvent in this class. This method is executed when a listening event occurs.

3. Event Publishing (ApplicationContext)

ApplicationContext is the core container in Spring and can act as the event publisher, or event source, in event listeners. Because the ApplicationContext inherited from ApplicationEventPublisher. Defines the method of event publishing – in ApplicationEventPublisher publishEvent (Object event)

4. Event management (ApplicationEventMulticaster)

ApplicationEventMulticaster used for event listener registration and broadcasting of events. It is used to register listeners by broadcasting events published by Applicationcontext to its list of listeners.

Fourth, actual combat demo

1. The entity class

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class StatsStuLearningTime {

    /** * class id */
    private String classId;
    
    /** ** **
    private Integer cucNo;
}
Copy the code

2. Event classes

You need to inherit from the ApplicationEvent class

public class StuLearntingSaveEvent<StatsStuLearningTime> extends ApplicationEvent {

    private StatsStuLearningTime statsStuLearningTime;

    public StuLearntingSaveEvent(Object source, StatsStuLearningTime statsStuLearningTime) {
        super(source);
        this.statsStuLearningTime = statsStuLearningTime;
    }

    public StatsStuLearningTime getStatsStuLearningTime(a){
        returnstatsStuLearningTime; }}Copy the code

3. Event Release Center

Here by Autowired injected ApplicationEventPublisher class

@Slf4j
@Component
public class LiveEventCenter {

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    /** * Release access live message event *@param statsStuLearningTime
     */
    public void publish(@NonNull StatsStuLearningTime statsStuLearningTime) {
        log.debug("start to publish live info event:[{}],", statsStuLearningTime);

        eventPublisher.publishEvent(new StuLearntingSaveEvent<>(this, statsStuLearningTime)); }}Copy the code

4. The observer

The key is the @EventListener annotation, which listens for events published by the observer and is used to implement Async

@Slf4j
@Service
public class ListenerBiz {

    @Autowired
    private RegisterRecordRPCService registerRecordRPCService;
    @Autowired
    private ClazzService clazzService;

    @Async
    @EventListener
    public void saveLiveInfo(StuLearntingSaveEvent<StatsStuLearningTime> stuLearntingSaveEvent){
        StatsStuLearningTime statsStuLearningTime = stuLearntingSaveEvent.getStatsStuLearningTime();
        // Call RPC interface to get student informationList<StudentsDto> studentsDtoList = registerRecordRPCService.queryStudentsByClassIdAndCucNum(clazzService.findCityCodeByClassId(statsStuLearningTime.getClas sId()), statsStuLearningTime.getClassId(), statsStuLearningTime.getCucNo());// Continue processing the data}}Copy the code

5. Publish events

Call the Publish method in the event publishing center to complete the event publishing

    @Autowired
    private LiveEventCenter eventCenter;
    
    // Release save student live data event
    resList.forEach(entity->{
        eventCenter.publish(entity);
    });
Copy the code

Five, the principle of brief discussion

1. The Spring framework provides four types of container events

  • ContextStartedEvent: ApplicationContext startup event;
  • ContextRefreshedEvent: ApplicationContext update event;
  • ContextStoppedEvent: ApplicationContext Stop event;
  • ContextClosedEvent: ApplicationContext close event.

2. Event listener

Direct definition

The EventListener ApplicationListener inherits from EventListener in the JDK, which requires all listeners to inherit it. The listener has only one method, onApplicationEvent, to handle the event ApplicationEvent.

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> 
    extends EventListener {
    void onApplicationEvent(E event);
}
Copy the code

When container startup of detection for the listener to achieve the user of the application of the listener registered to SimpleApplicationEventMulticaster collection.

Spring also supports event listening in the form of direct annotations, using the @EventListener annotation. When using annotations, methods can return any type, and if the return value is not null, they are republished as a new event.

Annotations to realize

@Service
public class AnnoEventListener {
    @EventListener
    public void listen(MyEvent myEvent){
        System.out.println("receive "+ myEvent.getSource()); }}Copy the code

Comments in the form of the listener is registered by EventListenerMethodProcessor in to the container. This class defines a Bean, upon the completion of the initialization, calls its rear afterSingletonsInstantiated callback methods, in the method of traverse all beans in the container, Extract the Methods decorated with the EventListener annotation and add an ApplicationListener object to the ApplicationContext listener list based on the annotation parameters.

3. Publish events

ApplicationEventPublisher interface defines the event publishing method, the code is as follows:

@FunctionalInterface
public interface ApplicationEventPublisher {
    default void publishEvent(ApplicationEvent event) {
        publishEvent((Object) event);
    }
    void publishEvent(Object event);
}
Copy the code

Inherited ApplicationEventPublisher ApplicationContext interface, and in the AbstractApplicationContext implements specific code, Actual execution is entrusted to ApplicationEventMulticaster.

ApplicationEventMulticaster interface definition to the operation of the listener, such as increasing the listener, remove the listener, and the method of publishing events. The default implementation SimpleApplicationEventMulticaster framework provides ApplicationEventMulticaster interface, If the local container no ApplicationEventMulticaster implementation will use the default implementation.

Can see in SimpleApplicationEventMulticaster multicastEvent method iterates through all of the Listener, and, in turn, calls the Listener onApplicationEvent methods publishing events. Spring also provides the ability to publish events asynchronously, which is executed asynchronously when taskExecutor is not null.

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
    @Nullable
    private Executor taskExecutor;
    @Override
    public void multicastEvent(final ApplicationEvent event, 
                               @Nullable ResolvableType eventType) { ResolvableType type = (eventType ! =null ? eventType : resolveDefaultEventType(event));
        for (finalApplicationListener<? > listener : getApplicationListeners(event, type)) { Executor executor = getTaskExecutor();if(executor ! =null) {
                executor.execute(() -> invokeListener(listener, event));
            }
            else{ invokeListener(listener, event); }}}}Copy the code