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

      

  • 相关阅读:
    前端css常用class命名id命名
    javaScript获取url问号后面的参数
    ASP.NET MVC 基础知识整理(一)
    Java基础概念(二)
    Java基础概念(一)
    ionic隐藏头部导航栏
    ionic开发中页面跳转隐藏底部Ttab
    /Date(1354116249000)/ 这样的格式怎么转成时间格式 JS
    ionic ng-repeat 循环传值
    ionic页面跳转传值 ng-click
  • 原文地址:https://www.cnblogs.com/coder-zyc/p/12232723.html
Copyright © 2020-2023  润新知