• (转)spring boot实战(第三篇)事件监听源码分析


    原文:http://blog.csdn.net/liaokailin/article/details/48194777

    监听源码分析

    首先是我们自定义的main方法:

    package com.lkl.springboot;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    import com.lkl.springboot.listener.MyApplicationStartedEventListener;
    
    @SpringBootApplication
    public class Application {
        public static void main(String[] args) {
            SpringApplication app = new SpringApplication(Application.class);
            //app.setAdditionalProfiles("dev");
            app.addListeners(new MyApplicationStartedEventListener());
            app.run(args);
        }
    }

    SpringApplication app = new SpringApplication(Application.class) 创建一个SpringApplication实例;创建实例执行对象构造方法;其构造方法如下:

       public SpringApplication(Object... sources) {
            this.bannerMode = Mode.CONSOLE;
            this.logStartupInfo = true;
            this.addCommandLineProperties = true;
            this.headless = true;
            this.registerShutdownHook = true;
            this.additionalProfiles = new HashSet();
            this.initialize(sources);
        }

    调用initialize(),该方法执行若干初始化操作,在后续再继续深入该方法。

    app.addListeners(new MyApplicationStartedEventListener()); 调用SpringApplication添加监听的方法执行操作:

        public void addListeners(ApplicationListener... listeners) {
            this.listeners.addAll(Arrays.asList(listeners));
        }

    this.listenersList<ApplicationListener<?>>类型,是SpringApplication中所有监听器的持有容器(initialize()方法中也会往该监听集合中添加初始化的监听器

    执行完添加监听器方法后执行app.run(args)方法

        public ConfigurableApplicationContext run(String... args) {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            ConfigurableApplicationContext context = null;
            this.configureHeadlessProperty();
            SpringApplicationRunListeners listeners = this.getRunListeners(args);
            listeners.started();
    
            try {
                DefaultApplicationArguments ex = new DefaultApplicationArguments(args);
                context = this.createAndRefreshContext(listeners, ex);
                this.afterRefresh(context, (ApplicationArguments)ex);
                listeners.finished(context, (Throwable)null);
                stopWatch.stop();
                if(this.logStartupInfo) {
                    (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
                }
    
                return context;
            } catch (Throwable var6) {
                this.handleRunFailure(context, listeners, var6);
                throw new IllegalStateException(var6);
            }
        }

    run()方法中完成了spring boot的启动,方法代码比较长,本篇重点放在事件监听上;

    SpringApplicationRunListeners listeners = this.getRunListeners(args);

    通过getRunListeners(args)获取执行时监听的集合,其代码如下:

        private SpringApplicationRunListeners getRunListeners(String[] args) {
            Class[] types = new Class[]{SpringApplication.class, String[].class};
            return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, new Object[]{this, args}));
        }

    重点关注

    
    
    private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args)
    这个方法返回
        private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            LinkedHashSet names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
            List instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
            AnnotationAwareOrderComparator.sort(instances);
            return instances;
        }

     SpringFactoriesLoader.loadFactoryNames(type, classLoader)

       public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
            String factoryClassName = factoryClass.getName();
    
            try {
                Enumeration ex = classLoader != null?classLoader.getResources("META-INF/spring.factories"):ClassLoader.getSystemResources("META-INF/spring.factories");
                ArrayList result = new ArrayList();
    
                while(ex.hasMoreElements()) {
                    URL url = (URL)ex.nextElement();
                    Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
                    String factoryClassNames = properties.getProperty(factoryClassName);
                    result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
                }
    
                return result;
            } catch (IOException var8) {
                throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);
            }
        }

    其中

    Enumeration ex = classLoader != null?classLoader.getResources("META-INF/spring.factories"):ClassLoader.getSystemResources("META-INF/spring.factories");

    通过类加载器获取resources; "META-INF/spring.factories"; 代码会去扫描项目工程中/META-INF下的spring.factories文件,获取org.springframework.boot.SpringApplicationRunListener对应数据 


    spring-boot-1.3.6.RELEASE中可以找到如下信息

    # Run Listeners
    org.springframework.boot.SpringApplicationRunListener=
    org.springframework.boot.context.event.EventPublishingRunListener

    即通过SpringApplicationRunListeners listeners = this.getRunListeners(args);最终拿到的是EventPublishingRunListener

     (这里还要做一个详细的回顾)

    在获取EventPublishingRunListener实例时,执行对应构造方法

        public EventPublishingRunListener(SpringApplication application, String[] args) {
            this.application = application;
            this.args = args;
            this.multicaster = new SimpleApplicationEventMulticaster();
            Iterator var3 = application.getListeners().iterator();
    
            while(var3.hasNext()) {
                ApplicationListener listener = (ApplicationListener)var3.next();
                this.multicaster.addApplicationListener(listener);
            }
    
        }

    SpringApplication中的监听器传递给SimpleApplicationEventMulticaster实例multicaster

    执行

            SpringApplicationRunListeners listeners = this.getRunListeners(args);
            listeners.started();        
        public void started() {
            Iterator var1 = this.listeners.iterator();
    
            while(var1.hasNext()) {
                SpringApplicationRunListener listener = (SpringApplicationRunListener)var1.next();
                listener.started();
            }
    
        }

    调用EventPublishingRunListener中的started()方法

      public void started() {
            this.publishEvent(new ApplicationStartedEvent(this.application, this.args));
        }

    在该方法中首先创建一个ApplicationStartedEvent事件,将this.application传递过去,因此在执行ApplicationStartedEvent监听时可以获取SpringApplication实例。

    执行publishEvent() 方法(这里就开始执行监听事件后调用的方法了)

        private void publishEvent(SpringApplicationEvent event) {
            this.multicaster.multicastEvent(event);
        }

    (这里还要分析一下multicaster接口的初始化)

    调用SimpleApplicationEventMulticaster#multicastEvent(event)

        public void multicastEvent(ApplicationEvent event) {
            this.multicastEvent(event, this.resolveDefaultEventType(event));
        }
    
        public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
            ResolvableType type = eventType != null?eventType:this.resolveDefaultEventType(event);
            Iterator var4 = this.getApplicationListeners(event, type).iterator();
    
            while(var4.hasNext()) {
                final ApplicationListener listener = (ApplicationListener)var4.next();
                Executor executor = this.getTaskExecutor();
                if(executor != null) {
                    executor.execute(new Runnable() {
                        public void run() {
                            SimpleApplicationEventMulticaster.this.invokeListener(listener, event);
                        }
                    });
                } else {
                    this.invokeListener(listener, event);
                }
            }
    
        }

    在该代码中需要注意的是for循环中获取监听器集合方getApplicationListeners(event),由于传递的事件为ApplicationStartedEvent,因此该方法需要获取到ApplicationStartedEvent对应的监听器

        protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
            Object source = event.getSource();
            Class sourceType = source != null?source.getClass():null;
            AbstractApplicationEventMulticaster.ListenerCacheKey cacheKey = new AbstractApplicationEventMulticaster.ListenerCacheKey(eventType, sourceType);
            AbstractApplicationEventMulticaster.ListenerRetriever retriever = (AbstractApplicationEventMulticaster.ListenerRetriever)this.retrieverCache.get(cacheKey);
            if(retriever != null) {
                return retriever.getApplicationListeners();
            } else if(this.beanClassLoader == null || ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader))) {
                Object var7 = this.retrievalMutex;
                synchronized(this.retrievalMutex) {
                    retriever = (AbstractApplicationEventMulticaster.ListenerRetriever)this.retrieverCache.get(cacheKey);
                    if(retriever != null) {
                        return retriever.getApplicationListeners();
                    } else {
                        retriever = new AbstractApplicationEventMulticaster.ListenerRetriever(true);
                        Collection listeners = this.retrieveApplicationListeners(eventType, sourceType, retriever);
                        this.retrieverCache.put(cacheKey, retriever);
                        return listeners;
                    }
                }
            } else {
                return this.retrieveApplicationListeners(eventType, sourceType, (AbstractApplicationEventMulticaster.ListenerRetriever)null);
            }
        }

    retrieveApplicationListeners(event, sourceType, null)方法;

        private Collection<ApplicationListener<?>> retrieveApplicationListeners(ResolvableType eventType, Class<?> sourceType, AbstractApplicationEventMulticaster.ListenerRetriever retriever) {
            LinkedList allListeners = new LinkedList();
            Object beanFactory = this.retrievalMutex;
            LinkedHashSet listeners;
            LinkedHashSet listenerBeans;
            synchronized(this.retrievalMutex) {
                listeners = new LinkedHashSet(this.defaultRetriever.applicationListeners);
                listenerBeans = new LinkedHashSet(this.defaultRetriever.applicationListenerBeans);
            }
    
            Iterator beanFactory1 = listeners.iterator();
    
            while(beanFactory1.hasNext()) {
                ApplicationListener listener = (ApplicationListener)beanFactory1.next();
                if(this.supportsEvent(listener, eventType, sourceType)) {
                    if(retriever != null) {
                        retriever.applicationListeners.add(listener);
                    }
    
                    allListeners.add(listener);
                }
            }
    
            if(!listenerBeans.isEmpty()) {
                BeanFactory beanFactory2 = this.getBeanFactory();
                Iterator listener2 = listenerBeans.iterator();
    
                while(listener2.hasNext()) {
                    String listenerBeanName = (String)listener2.next();
    
                    try {
                        Class listenerType = beanFactory2.getType(listenerBeanName);
                        if(listenerType == null || this.supportsEvent(listenerType, eventType)) {
                            ApplicationListener listener1 = (ApplicationListener)beanFactory2.getBean(listenerBeanName, ApplicationListener.class);
                            if(!allListeners.contains(listener1) && this.supportsEvent(listener1, eventType, sourceType)) {
                                if(retriever != null) {
                                    retriever.applicationListenerBeans.add(listenerBeanName);
                                }
    
                                allListeners.add(listener1);
                            }
                        }
                    } catch (NoSuchBeanDefinitionException var13) {
                        ;
                    }
                }
            }
    
            AnnotationAwareOrderComparator.sort(allListeners);
            return allListeners;
        }

    调用supportsEvent方法判断对应的监听器是否支持指定的事件

        protected boolean supportsEvent(ApplicationListener<?> listener, ResolvableType eventType, Class<?> sourceType) {
            Object smartListener = listener instanceof GenericApplicationListener?(GenericApplicationListener)listener:new GenericApplicationListenerAdapter(listener);
            return ((GenericApplicationListener)smartListener).supportsEventType(eventType) && ((GenericApplicationListener)smartListener).supportsSourceType(sourceType);
        }

    执行 GenericApplicationListenerAdapter#supportsEventType(eventType)

        public boolean supportsEventType(ResolvableType eventType) {
            if(this.delegate instanceof SmartApplicationListener) {
                Class eventClass = eventType.getRawClass();
                return ((SmartApplicationListener)this.delegate).supportsEventType(eventClass);
            } else {
                return this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType);
            }
        }

    GenericTypeResolver泛型解析工具类功能强大,我们在实际开发中同样可以利用。

    至此getApplicationListeners(event)调用完成,大体思路为:遍历所有的监听器,如果该监听器监听的事件为传递的事件或传递事件的父类则表示该监听器支持指定事件。

    获取完指定事件对应监听器后,通过Executor执行一个子线程去完成监听器listener.onApplicationEvent(event)方法。

  • 相关阅读:
    工作流-1
    net core体系-Xamarin-2概要(lignshi)
    net core体系-web应用程序-4asp.net core2.0 项目实战(CMS)-第二章 入门篇-快速入门ASP.NET Core看这篇就够了
    手机支持NFC
    net core体系-Standard-1概述
    运营-赵本山最近有点烦:二人转产业链滑铁卢 关联公司IPO预披露
    MSSql-1内部数据库版本号
    (JAVA保留小数问题,基础)Probability hdu2131
    (stripTrailingZeros)A == B hdu2054
    (reverse)Palindromes hdu2163
  • 原文地址:https://www.cnblogs.com/guazi/p/6709882.html
Copyright © 2020-2023  润新知