zoukankan      html  css  js  c++  java
  • Spring:ApplicationListener用法及原理

    ApplicationListener

    监听容器中发布的事件,时间驱动模型开发。

    //监听ApplicationEvent事件
    public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    	//容器中发布此事件后,此方法会触发
    	void onApplicationEvent(E event);
    
    }
    

    代码:

    @Component
    public class MyApplicationListener implements ApplicationListener {
    
        @Override
        public void onApplicationEvent(ApplicationEvent event) {
            System.out.println("收到事件:"+ event);
        }
    }
    
    @ComponentScan
    @Configuration
    public class ExtConfig {
    }
    

    测试方法:

    public class MainTest {
        public static void main(String[] args) {
    
            ApplicationContext applicationContext  = new AnnotationConfigApplicationContext(ExtConfig.class);
            ((AnnotationConfigApplicationContext) applicationContext).close();
        }
    }
    

    image-20210315212133605

    收到两个事件:容器刷新和容器关闭事件。

    步骤:1.写一个监听器来监听某个事件

    2.把监听器加入到容器

    3.容器只要发布相关事件,我们就能监听到该事件

    用法有点像mq,不过是spring容器内的监听。

    ApplicationContext applicationContext  = new AnnotationConfigApplicationContext(ExtConfig.class);
    
    applicationContext.publishEvent(new ApplicationEvent("hello") {
        @Override
        public Object getSource() {
            return super.getSource();
        }
    });
    
    ((AnnotationConfigApplicationContext) applicationContext).close();
    

    image-20210315212729768

    实现原理

    ContextRefreshedEvent事件

    创建容器时,会调用容器的refresh方法:

    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();
    
            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);
    
            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);
    
                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);
    
                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);
    
                // Initialize message source for this context.
                initMessageSource();
    
                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();
    
                // Initialize other special beans in specific context subclasses.
                onRefresh();
    
                // Check for listener beans and register them.
                registerListeners();
    
                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);
    
                // Last step: publish corresponding event.
                finishRefresh();
            }
    
            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                                "cancelling refresh attempt: " + ex);
                }
    
                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();
    
                // Reset 'active' flag.
                cancelRefresh(ex);
    
                // Propagate exception to caller.
                throw ex;
            }
    
            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }
    

    最后一步:finishRefresh

    	protected void finishRefresh() {
    		// 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方法的最终实现:

    	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 {
                //获取到事件的派发器,调用multicastEvent方法派发事件
    			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);
    			}
    		}
    	}
    

    派发方法源码:

    @Override
    public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        //获取所有事件监听器
        for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            Executor executor = getTaskExecutor();
            if (executor != null) {
                //异步处理
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        invokeListener(listener, event);
                    }
                });
            }
            else {
                //直接调用invokeListener
                invokeListener(listener, event);
            }
        }
    }
    

    invokeListener方法:调用doInvokeListener方法

    image-20210315213705786

    image-20210315213818939

    手动发布事件

    还是调用publishEvent方法

    image-20210315214116567

    容器关闭

    调用doClose方法:

    image-20210315214227817

    image-20210315214259652

    事件派发器的创建

    容器启动时,调用refresh方法,其中有一步就初始化好了一些事件派发器

    image-20210315214510810

    initApplicationEventMulticaster()方法:

    protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        //先去容器中查找是否存在id=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 {
            //如果没有,就直接创建一个简单事件派发器
            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 + "]");
            }
        }
    }
    

    ApplicationListener

    refresh方法会有一步注册监听器

    image-20210315215145510

    registerListeners方法:

    image-20210315215457069

    @EventListener用法和原理

    通过标注在方法上的@EventListener注解,一旦监听到指定事件后,就会调用该方法。

    @Component
    public class MyApplicationListener implements ApplicationListener {
    
        @Override
        public void onApplicationEvent(ApplicationEvent event) {
            System.out.println("收到事件:"+ event);
        }
    
        @EventListener(ApplicationEvent.class)
        public void listener(ApplicationEvent event){
            System.out.println("listener:"+event);
        }
    }
    

    image-20210315220219223

    EventListener原理:EventListenerMethodProcessor处理器

    public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware
    

    该类实现了SmartInitializingSingleton接口,afterSingletonsInstantiated方法会在所有单实例bean创建完成后调用

    public interface SmartInitializingSingleton {
    
    	/**
    	 * Invoked right at the end of the singleton pre-instantiation phase,
    	 * with a guarantee that all regular singleton beans have been created
    	 * already. {@link ListableBeanFactory#getBeansOfType} calls within
    	 * this method won't trigger accidental side effects during bootstrap.
    	 * <p><b>NOTE:</b> This callback won't be triggered for singleton beans
    	 * lazily initialized on demand after {@link BeanFactory} bootstrap,
    	 * and not for any other bean scope either. Carefully use it for beans
    	 * with the intended bootstrap semantics only.
    	 */
    	void afterSingletonsInstantiated();
    
    }
    

    具体实现:容器创建调用refresh时,调用了finishBeanFactoryInitialization方法

    image-20210315220613173

    调用了beanFactory.preInstantiateSingletons()方法

    image-20210315220655428

    该方法前面在创建所有的单实例bean,该方法的最后:

    image-20210315221116124

    因为EventListenerMethodProcessor实现了SmartInitializingSingleton接口,所以被调用了afterSingletonsInstantiated方法,该方法最主要调用了processBean方法:

    image-20210315222149336

    processBean方法实现如下:

    protected void processBean(final List<EventListenerFactory> factories, final String beanName, final Class<?> targetType) {
        if (!this.nonAnnotatedClasses.contains(targetType)) {
            Map<Method, EventListener> annotatedMethods = null;
            try {
                //获取方法上标注了EventListener注解的方法
                annotatedMethods = MethodIntrospector.selectMethods(targetType,
                                                                    new MethodIntrospector.MetadataLookup<EventListener>() {
                                                                        @Override
                                                                        public EventListener inspect(Method method) {
                                                                            return AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class);
                                                                        }
                                                                    });
            }
            catch (Throwable ex) {
                // An unresolvable type in a method signature, probably from a lazy bean - let's ignore it.
                if (logger.isDebugEnabled()) {
                    logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex);
                }
            }
            if (CollectionUtils.isEmpty(annotatedMethods)) {
                this.nonAnnotatedClasses.add(targetType);
                if (logger.isTraceEnabled()) {
                    logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
                }
            }
            else {
                // Non-empty set of methods
                for (Method method : annotatedMethods.keySet()) {
                    for (EventListenerFactory factory : factories) {
                        if (factory.supportsMethod(method)) {
                            Method methodToUse = AopUtils.selectInvocableMethod(
                                method, this.applicationContext.getType(beanName));
                            //创建ApplicationListenerMethodAdapter适配器
                            ApplicationListener<?> applicationListener =
                                factory.createApplicationListener(beanName, targetType, methodToUse);
                            if (applicationListener instanceof ApplicationListenerMethodAdapter) {
                                //设置适配器的一些属性
                                ((ApplicationListenerMethodAdapter) applicationListener)
                                .init(this.applicationContext, this.evaluator);
                            }
                            //IOC容器中添加该时适配器(该适配器已经实现了ApplicationListener接口)					
                            this.applicationContext.addApplicationListener(applicationListener);
                            break;
                        }
                    }
                }
                if (logger.isDebugEnabled()) {
                    logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
                                 beanName + "': " + annotatedMethods);
                }
            }
        }
    }
    
  • 相关阅读:
    蓝桥杯 买不到的数目(动态规划)
    部分ftp登不上原因
    glColor3f()函数 表示颜色
    三维模型(X,Y,Z)坐标,UV坐标
    找不到 Windows SDK 版本10.0.18362.0的解决办法
    头文件中的ifndef/define/endif有什么作用?
    pycharm 出现opencv(4.4.0)等等错误如何解决
    灵敏度分析与误差分析
    死磕Spring之AOP篇
    死磕Spring之IoC篇
  • 原文地址:https://www.cnblogs.com/wwjj4811/p/14540493.html
Copyright © 2011-2022 走看看