码迷,mamicode.com
首页 > 编程语言 > 详细

Spring 事件监听

时间:2020-01-25 01:00:26      阅读:109      评论:0      收藏:0      [点我收藏+]

标签:类型   ima   ssi   RoCE   oca   contexts   his   清理   throw   

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

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

   

  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);
    }
}

  

  

  • 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;
        }
    }
}

  

 

Spring 事件监听

标签:类型   ima   ssi   RoCE   oca   contexts   his   清理   throw   

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!