Elegant programming - SpringEvent

SpringEvent event-driven introduction

Spring in the event-driven model is also known as publish-subscribe model, is the presence of three roles of a typical Spring application event-driven model observer mode: Event prototype, the event publisher, event listeners.

Spring Event prototype

Spring event is defined by ApplicationEvent, the class inherits from Jdk of EventObject; JDK requires that all events will inherit it, and get event source by source, such as our AWT event system is inherited from it;

ApplicationEvent specification are defined as follows:

public abstract class ApplicationEvent extends EventObject {

	/** use serialVersionUID from Spring 1.2 for interoperability */
	private static final long serialVersionUID = 7099057708183571937L;

	/** System time when the event happened */
	private final long timestamp;

	/**
	 * Create a new ApplicationEvent.
	 * @param source the object on which the event initially occurred (never {@code null})
	 */
	public ApplicationEvent(Object source) {
		super(source);
		this.timestamp = System.currentTimeMillis();
	}

	/**
	 * Return the system time in milliseconds when the event happened.
	 */
	public final long getTimestamp() {
		return this.timestamp;
	}
}
复制代码

Spring Event Publisher

Spring event publishing specifications defined in ApplicationEventPublisher, mainly for the event publisher publishing event;

ApplicationEventPublisher specification are defined as follows:

public interface ApplicationEventPublisher {

	/**
	 * Notify all <strong>matching</strong> listeners registered with this
	 * application of an application event. Events may be framework events
	 * (such as RequestHandledEvent) or application-specific events.
	 * @param event the event to publish
	 * @see org.springframework.web.context.support.RequestHandledEvent
	 */
	void publishEvent(ApplicationEvent event);

	/**
	 * Notify all <strong>matching</strong> listeners registered with this
	 * application of an event.
	 * <p>If the specified {@code event} is not an {@link ApplicationEvent},
	 * it is wrapped in a {@link PayloadApplicationEvent}.
	 * @param event the event to publish
	 * @since 4.2
	 * @see PayloadApplicationEvent
	 */
	void publishEvent(Object event);
}
复制代码

ApplicationContext interface is integrated ApplicationEventPublisher, as shown:

image

For ApplicationContext, Spring provides a default implementation, in the abstract class AbstractApplicationContext in common AnnotationConfigWebApplicationContext, ClassPathXmlApplicationContext, FileSystemXmlApplicationContexthas inherited behavior AbstractApplicationContext of events:

AbstractApplicationContext class codes are as follows:

/**
 * Publish the given event to all listeners.
 * @param event the event to publish (may be an {@link ApplicationEvent}
 * or a payload object to be turned into a {@link PayloadApplicationEvent})
 * @param eventType the resolved event type, if known
 * @since 4.2
 */
protected void publishEvent(Object event, ResolvableType eventType) {
    Assert.notNull(event, "Event must not be null");
    if (logger.isTraceEnabled()) {
        logger.trace("Publishing event in " + getDisplayName() + ": " + event);
    }

    // Decorate event as an ApplicationEvent if necessary
    ApplicationEvent applicationEvent;
    if (event instanceof ApplicationEvent) {
        applicationEvent = (ApplicationEvent) event;
    }
    else {
        applicationEvent = new PayloadApplicationEvent<Object>(this, event);
        if (eventType == null) {
            eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
        }
    }

    // Multicast right now if possible - or lazily once the multicaster is initialized
    if (this.earlyApplicationEvents != null) {
        this.earlyApplicationEvents.add(applicationEvent);
    }
    else {
        getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    }

    // Publish event via parent context as well...
    if (this.parent != null) {
        if (this.parent instanceof AbstractApplicationContext) {
            ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
        }
        else {
            this.parent.publishEvent(event);
        }
    }
}
复制代码

In this method, we see a getApplicationEventMulticaster (); ApplicationEventMulticaster belongs to the event broadcaster, its role is to ApplicationContext released Event broadcast to all listeners.

Spring event listener

Spring ApplicationListener is defined in event monitoring those norms, defined as follows:

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
	/**
	 * Handle an application event.
	 * @param event the event to respond to
	 */
	void onApplicationEvent(E event);
}
复制代码

Inherited from ApplicationListener EventListener jdk all listeners must implement this interface, this interface is only a onApplicationEvent () method, which accepts a ApplicationEvent or subclass object as a parameter, in the process of the body may be different based on the Event judgment to the appropriate treatment. when an event triggers all the listeners will receive a message if you need to have requirements, you can implement a sub-interface SmartApplicationListener this interface, you can specify the listener through this interface receives order for listeners receiving the sequence of events.

Interface integrated relationship SmartApplicationListener as follows:

image

SpringEvent event application examples

Event Definition

public class PlanAllocatePubEvent extends ApplicationEvent {

    public PlanAllocatePubEvent(Long allocateId) {
        super(allocateId);
    }
}
复制代码

Event Publishing

@Component
public class PlanAllocatePubPublisher {

    private static final Logger LOG = LoggerFactory.getLogger(PlanAllocatePubPublisher.class);

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    public void publishEvent(long allocateId){
        LOG.info("[事件发布] 数据创建, 编号:" + allocateId);
        PlanAllocatePubEvent event = new PlanAllocatePubEvent(allocateId);
        applicationEventPublisher.publishEvent(event);
    }
}
复制代码

Event listener (disorder)

Synchronous event processing

@Component
public class SyncPlanAllocatePubListener implements ApplicationListener<PlanAllocatePubEvent>{

    private static final Logger LOG = LoggerFactory.getLogger(SyncPlanAllocatePubListener.class);

    @Override
    public void onApplicationEvent(PlanAllocatePubEvent planAllocatePubEvent) {
        LOG.info("[同步][事件监听][开始]数据创建, 数据编号:" + planAllocatePubEvent.getSource());
        doSomething();
        LOG.info("[同步][事件监听][结束]数据创建, 数据编号:" + planAllocatePubEvent.getSource());
    }

    public void doSomething(){
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            LOG.error(e.getLocalizedMessage(), e);
        }
    }

}
复制代码

Asynchronous event handling

@Component
@EnableAsync
public class AsynPlanAllocatePubListener implements ApplicationListener<PlanAllocatePubEvent> {

    private static final Logger LOG = LoggerFactory.getLogger(AsynPlanAllocatePubListener.class);

    @Async
    @Override
    public void onApplicationEvent(PlanAllocatePubEvent planAllocatePubEvent) {
        LOG.info("[异步][事件监听][开始]数据创建, 数据编号:" + planAllocatePubEvent.getSource());
        doSomething();
        LOG.info("[异步][事件监听][结束]数据创建, 数据编号:" + planAllocatePubEvent.getSource());
    }

    public void doSomething(){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            LOG.error(e.getLocalizedMessage(), e);
        }
    }

}
复制代码

Event listener (ordered)

Sample code: event listener logic 1

@Component
public class Order1PlanAllocatePubListener implements SmartApplicationListener {

    private static final Logger LOG = LoggerFactory.getLogger(Order1PlanAllocatePubListener.class);

    /**
     * supportsEventType用于指定支持的事件类型,只有支持的才调用onApplicationEvent
     * @param eventType
     * @return
     */
    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
        return eventType == PlanAllocatePubEvent.class;
    }

    /**
     * supportsSourceType支持的目标类型,只有支持的才调用onApplicationEvent
     * @param sourceType
     * @return
     */
    @Override
    public boolean supportsSourceType(Class<?> sourceType) {
        return sourceType == Long.class;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        LOG.info("[有序事件][事件监听][Order:1]数据创建, 编号:" + event.getSource());
        doSomething();
    }

    /**
     * 优先级顺序,越小优先级越高
     * @return
     */
    @Override
    public int getOrder() {
        return 1;
    }

    public void doSomething(){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            LOG.error(e.getLocalizedMessage(), e);
        }
    }
}
复制代码

Sample code: event listener Logic 2

@Component
public class Order2PlanAllocatePubListener implements SmartApplicationListener{

    private static final Logger LOG =  LoggerFactory.getLogger(Order2PlanAllocatePubListener.class);

    /**
     * supportsEventType用于指定支持的事件类型,只有支持的才调用onApplicationEvent
     * @param eventType
     * @return
     */
    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
        return eventType == PlanAllocatePubEvent.class;
    }

    /**
     * supportsSourceType支持的目标类型,只有支持的才调用onApplicationEvent
     * @param sourceType
     * @return
     */
    @Override
    public boolean supportsSourceType(Class<?> sourceType) {
        return sourceType == Long.class;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        LOG.info("[有序事件][事件监听][Order:2]数据创建, 编号:" + event.getSource());
        doSomething();
    }

    /**
     * 优先级顺序,越小优先级越高
     * @return
     */
    @Override
    public int getOrder() {
        return 2;
    }

    public void doSomething(){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            LOG.error(e.getLocalizedMessage(), e);
        }
    }
}
复制代码

Test event


@Controller
@RequestMapping(value = "/api/event")
public class ApiPluginEventController {

    @Autowired
    private PlanAllocatePubPublisher planAllocatePubPublisher;

    @ResponseBody
    @GetMapping(value = "/publish")
    public Map pubEvent() throws Exception {
        for(int i=1; i<5; i++){
            planAllocatePubPublisher.publishEvent(i);
        }
        return ImmutableMap.builder().put("message", "ok").build();
    }
}
复制代码
The results of asynchronous events
INFO:2017-09-11 20:14:08.799[publishEvent] [事件发布] 数据创建, 数据编号:1 
INFO:2017-09-11 20:14:08.803[publishEvent] [事件发布] 数据创建, 数据编号:2 
INFO:2017-09-11 20:14:08.803[onApplicationEvent] [异步][事件监听][开始]数据创建, 数据编号:1 
INFO:2017-09-11 20:14:08.804[publishEvent] [事件发布] 数据创建, 数据编号:3 
INFO:2017-09-11 20:14:08.804[onApplicationEvent] [异步][事件监听][开始]数据创建, 数据编号:2 
INFO:2017-09-11 20:14:08.805[onApplicationEvent] [异步][事件监听][开始]数据创建, 数据编号:3 
INFO:2017-09-11 20:14:08.804[publishEvent] [事件发布] 数据创建, 数据编号4 
INFO:2017-09-11 20:14:08.805[onApplicationEvent] [异步][事件监听][开始]数据创建, 数据编号:4 
INFO:2017-09-11 20:14:11.807[onApplicationEvent] [异步][事件监听][结束]数据创建, 数据编号:1 
INFO:2017-09-11 20:14:11.807[onApplicationEvent] [异步][事件监听][结束]数据创建, 数据编号:2 
INFO:2017-09-11 20:14:11.807[onApplicationEvent] [异步][事件监听][结束]数据创建, 数据编号:3 
INFO:2017-09-11 20:14:11.809[onApplicationEvent] [异步][事件监听][结束]数据创建, 数据编号:4 
复制代码
The results of synchronization events
INFO:2017-09-11 20:17:07.470[publishEvent] [事件发布] 数据创建, 数据编号:1 
INFO:2017-09-11 20:17:07.473[onApplicationEvent] [同步][事件监听][开始]数据创建, 数据编号:1 
INFO:2017-09-11 20:17:09.476[onApplicationEvent] [同步][事件监听][结束]数据创建, 数据编号:1 
INFO:2017-09-11 20:17:09.477[publishEvent] [事件发布] 数据创建, 数据编号:2 
INFO:2017-09-11 20:17:09.478[onApplicationEvent] [同步][事件监听][开始]数据创建, 数据编号:2 
INFO:2017-09-11 20:17:11.481[onApplicationEvent] [同步][事件监听][结束]数据创建, 数据编号:2 
INFO:2017-09-11 20:17:11.481[publishEvent] [事件发布] 数据创建, 数据编号:3 
INFO:2017-09-11 20:17:11.482[onApplicationEvent] [同步][事件监听][开始]数据创建, 数据编号:3 
INFO:2017-09-11 20:17:13.486[onApplicationEvent] [同步][事件监听][结束]数据创建, 数据编号:3 
INFO:2017-09-11 20:17:13.487[publishEvent] [事件发布] 数据创建, 数据编号:4 
INFO:2017-09-11 20:17:13.487[onApplicationEvent] [同步][事件监听][开始]数据创建, 数据编号:4 
INFO:2017-09-11 20:17:15.492[onApplicationEvent] [同步][事件监听][结束]数据创建, 数据编号:4 
复制代码
Ordered event execution results
INFO:2017-09-11 20:33:12.139[publishEvent] [事件发布] 数据创建, 编号:1 
INFO:2017-09-11 20:33:12.140[onApplicationEvent] [有序事件][事件监听][Order:1]数据创建, 编号:1 
INFO:2017-09-11 20:33:15.145[onApplicationEvent] [有序事件][事件监听][Order:2]数据创建, 编号:1 
INFO:2017-09-11 20:33:18.146[publishEvent] [事件发布] 数据创建, 编号:2 
INFO:2017-09-11 20:33:18.147[onApplicationEvent] [有序事件][事件监听][Order:1]数据创建, 编号:2 
INFO:2017-09-11 20:33:21.151[onApplicationEvent] [有序事件][事件监听][Order:2]数据创建, 编号:2 
INFO:2017-09-11 20:33:24.156[publishEvent] [事件发布] 数据创建, 编号:3 
INFO:2017-09-11 20:33:24.157[onApplicationEvent] [有序事件][事件监听][Order:1]数据创建, 编号:3 
INFO:2017-09-11 20:33:27.162[onApplicationEvent] [有序事件][事件监听][Order:2]数据创建, 编号:3 
INFO:2017-09-11 20:33:30.167[publishEvent] [事件发布] 数据创建, 编号:4 
INFO:2017-09-11 20:33:30.168[onApplicationEvent] [有序事件][事件监听][Order:1]数据创建, 编号:4 
INFO:2017-09-11 20:33:33.171[onApplicationEvent] [有序事件][事件监听][Order:2]数据创建, 编号:4 
复制代码

Notes Event Listeners

Spring4.2 began offering a @EventListener notes, making the listener no longer need to implement ApplicationListener interfaces, only need to add to the comment on the monitor method, the method is not necessarily called onApplicationEvent, but there is one and only one parameter, the specified listener . the event type logic ordered event listener in the example above can use annotations ways:

@Component
public class PlanAllocatePubHandler {

    private static final Logger LOG = LoggerFactory.getLogger(PlanAllocatePubHandler.class);

    /**
     * 基于注解的事件监听
     * @param planAllocatePubEvent
     */
    @EventListener
    @Order(1)
    public void annoEnvListener1(PlanAllocatePubEvent planAllocatePubEvent) {
        LOG.info("[注解事件监听][Order:1]数据创建, 编号:" + planAllocatePubEvent.getSource());
        doSomething();
    }

    /**
     * 基于注解的事件监听
     * @param planAllocatePubEvent
     */
    @EventListener
    @Order(2)
    public void annoEnvListener2(PlanAllocatePubEvent planAllocatePubEvent) {
        LOG.info("[注解事件监听][Order:2]数据创建, 编号:" + planAllocatePubEvent.getSource());
        doSomething();
    }

    public void doSomething(){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            LOG.error(e.getLocalizedMessage(), e);
        }
    }
}
复制代码
Notes event listener execution results
INFO:2017-09-11 20:57:00.167[publishEvent] [事件发布] 数据创建, 编号:1 
INFO:2017-09-11 20:57:00.168[annoEnvListener1] [注解事件监听][Order:1]数据创建, 编号:1 
INFO:2017-09-11 20:57:03.169[annoEnvListener2] [注解事件监听][Order:2]数据创建, 编号:1 
INFO:2017-09-11 20:57:06.175[publishEvent] [事件发布] 数据创建, 编号:2 
INFO:2017-09-11 20:57:06.176[annoEnvListener1] [注解事件监听][Order:1]数据创建, 编号:2 
INFO:2017-09-11 20:57:09.180[annoEnvListener2] [注解事件监听][Order:2]数据创建, 编号:2 
INFO:2017-09-11 20:57:12.184[publishEvent] [事件发布] 数据创建, 编号:3 
INFO:2017-09-11 20:57:12.185[annoEnvListener1] [注解事件监听][Order:1]数据创建, 编号:3 
INFO:2017-09-11 20:57:15.191[annoEnvListener2] [注解事件监听][Order:2]数据创建, 编号:3 
INFO:2017-09-11 20:57:18.195[publishEvent] [事件发布] 数据创建, 编号:4 
INFO:2017-09-11 20:57:18.196[annoEnvListener1] [注解事件监听][Order:1]数据创建, 编号:4 
INFO:2017-09-11 20:57:21.198[annoEnvListener2] [注解事件监听][Order:2]数据创建, 编号:4 
复制代码

Guess you like

Origin juejin.im/post/5dfb2b6d51882512275313fa