Spring 事件监听

  Spring 的核心是 ApplicationContext,它负责管理 Bean的完整生命周期;当加载 Bean 时,ApplicationContext 发布某些类型的事件;例如,当上下文启动时,ContextStartedEvent 发布消息,当上下文停止时,ContextStoppedEvent 发布消息;

  通过 ApplicationEvent 类和 ApplicationListener 接口来提供在 ApplicationContext 中处理事件;如果一个 Bean 实现 ApplicationListener 接口,那么每次 ApplicationEvent 被发布到 ApplicationContext 上,那个 Bean实例会被通知;类似MQ的发布订阅;

   

  ApplicationEvent UML图如下:

  

  • Spring常用事件

序号Spring 事件
1 ContextRefreshedEvent:ApplicationContext 被初始化或刷新时,该事件被发布;这也可以在 ConfigurableApplicationContext 接口中使用 refresh() 方法来发生;容器刷新完成(所有bean都完全创建)会发布这个事件;
2 ContextStartedEvent:当使用 ConfigurableApplicationContext 接口中的 start() 方法启动 ApplicationContext 时,该事件被发布;
3 ContextStoppedEvent:当使用 ConfigurableApplicationContext 接口中的 stop() 方法停止 ApplicationContext 时,发布这个事件;
4 ContextClosedEvent:当使用 ConfigurableApplicationContext 接口中的 close() 方法关闭 ApplicationContext 时,该事件被发布;
5 RequestHandledEvent:在Web应用中,当一个http请求结束触发该事件

 

  • ApplicationContext

  ApplicationContext即应用上下文,继承自BeanFactory接口,可用于获取Spring 管理的Bean对象实例;

  ApplicationContextAware:Aware是属性注入,ApplicationContextAware与ApplicationContext不同的是,当Spring容器初始化的时候,实现了 ApplicationContextAware 接口的 Bean会自动注入ApplicationContext;

 

  使用如下:

    自定义ApplicationContextAware

@Component
public class ApplicationContextProvider implements ApplicationContextAware {
    private ApplicationContext applicationContext;

    /**
     * 上下文实例
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * 获取上下文
     * @return
     */
    public ApplicationContext getApplicationContext() {
        return this.applicationContext;
    }

    /**
     * 通过类名获取Bean实例
     * @param name
     * @return
     */
    public Object getBean(String name) {
        return this.applicationContext.getBean(name);
    }

    /**
     * 通过字节码获取Bean实例
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T getBean(Class<T> clazz) {
        return this.applicationContext.getBean(clazz);
    }
}

  

    自定义监听器

@Slf4j
@Component
public class MyListener implements ApplicationListener {

    @Override
    public void onApplicationEvent(ApplicationEvent event) {

        if (event instanceof MyApplicationEvent) {
            log.info("recv:" + event);
        } else {
            log.info("recv 容器本身:" + event);
        }
    }
}

  

    自定义事件

public class MyApplicationEvent extends ApplicationEvent {
    private Person person;

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    public MyApplicationEvent(Object source, Person person) {
        super(source);
        this.person = person;
    }

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

  

    在controller添加一个发布事件的方法

@Autowired
private ApplicationContextProvider provider;

@GetMapping("/publish")
public String publish() {
    ApplicationContext applicationContext = provider.getApplicationContext();
    Person person = new Person();
    person.setId(1);
    person.setAddress("chn");
    person.setName("test");
    person.setPhone("123");

    applicationContext.publishEvent(new MyApplicationEvent(person) {
    });
    log.info("applicationContext:{}", applicationContext);

    return "applicationContext: " + applicationContext;
}

  当往/publish这个映射发请求的时候,publishEvent方法会发送事件;监听器就会就会接收;

  

  • ApplicationListener

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

	/**
	 * Handle an application event.
	 * @param event the event to respond to
	 */
	void onApplicationEvent(E event);

}

  

  ApplicationListener监听ApplicationEvent及其子类的事件;

  AbstractApplicationContext.java

public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext {
    ...
}

  

  ConfigurableApplicationContext:SPI接口将由大多数应用程序上下文实现;除了提供中的应用程序上下文客户端方法外,还提供了配置应用程序上下文的功能在ApplicationContext接口;

  refresh方法执行容器的加载

public void refresh() throws BeansException, IllegalStateException {
    ...
    // Initialize event multicaster for this context.
    initApplicationEventMulticaster();
    
    ...
    // Last step: publish corresponding event.
	finishRefresh();
    ...
    
}


protected void initApplicationEventMulticaster() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    //查找容器中是否存在"applicationEventMulticaster"的组件
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        this.applicationEventMulticaster =
            beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
        if (logger.isDebugEnabled()) {
            logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
        }
    }
    else {
        //没有则new "applicationEventMulticaster"的组件,并加入到容器中,注入到"applicationEventMulticaster",registerSingleton会在存储所有注册的监听器map中查找监听器是否存在,不存在则往map中执行put操作
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
        if (logger.isDebugEnabled()) {
            logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
                         APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
                         "': using default [" + this.applicationEventMulticaster + "]");
        }
    }
}

  

  finshRefresh方法

protected void finishRefresh() {
    // Clear context-level resource caches (such as ASM metadata from scanning).
    clearResourceCaches();

    // Initialize lifecycle processor for this context.
    initLifecycleProcessor();

    // Propagate refresh to lifecycle processor first.
    getLifecycleProcessor().onRefresh();

    // Publish the final event.
    publishEvent(new ContextRefreshedEvent(this));

    // Participate in LiveBeansView MBean, if active.
    LiveBeansView.registerApplicationContext(this);
}

  

  publishEvent方法 发布事件

@Override
public void publishEvent(ApplicationEvent event) {
    publishEvent(event, null);
}


protected void publishEvent(Object event, @Nullable 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<>(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...
    // 判断当前ApplicationContext有没有父级ApplicationContext
    if (this.parent != null) {
        if (this.parent instanceof AbstractApplicationContext) {
            ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
        }
        else {
            this.parent.publishEvent(event);
        }
    }
}

  

  AbstractApplicationEventMulticaster提供基本的监听器注册功能

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

}

  

  SimpleApplicationEventMulticaster.java

//将给定的应用程序事件分发到对应的监听器
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        Executor executor = getTaskExecutor();
        if (executor != null) {
            executor.execute(() -> invokeListener(listener, event));
        }
        else {
            invokeListener(listener, event);
        }
    }
}

//调用给定事件的监听器
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
    ErrorHandler errorHandler = getErrorHandler();
    if (errorHandler != null) {
        try {
            doInvokeListener(listener, event);
        }
        catch (Throwable err) {
            errorHandler.handleError(err);
        }
    }
    else {
        doInvokeListener(listener, event);
    }
}


private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
    try {
        //调用实现ApplicationListener接口的onApplicationEvent方法
        listener.onApplicationEvent(event);
    }
    catch (ClassCastException ex) {
        String msg = ex.getMessage();
        if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
            // Possibly a lambda-defined listener which we could not resolve the generic event type for
            // -> let's suppress the exception and just log a debug message.
            Log logger = LogFactory.getLog(getClass());
            if (logger.isDebugEnabled()) {
                logger.debug("Non-matching event type for listener: " + listener, ex);
            }
        }
        else {
            throw ex;
        }
    }
}

  

原文地址:https://www.cnblogs.com/coder-zyc/p/12232723.html