spring boot 2.0 源码分析(二)

在上一章学习了spring boot 2.0启动的大概流程以后,今天我们来深挖一下SpringApplication实例变量的run函数。

先把这段run函数的代码贴出来:

/**

    * Run the Spring application, creating and refreshing a new

    * {@link ApplicationContext}.

    * @param args the application arguments (usually passed from a Java main method)

    * @return a running {@link ApplicationContext}

    */publicConfigurableApplicationContext run(String... args) {        StopWatch stopWatch =newStopWatch();        stopWatch.start();        ConfigurableApplicationContext context =null;        Collection exceptionReporters =newArrayList<>();        configureHeadlessProperty();        SpringApplicationRunListeners listeners = getRunListeners(args);        listeners.starting();try{            ApplicationArguments applicationArguments =newDefaultApplicationArguments(                    args);            ConfigurableEnvironment environment = prepareEnvironment(listeners,                    applicationArguments);            configureIgnoreBeanInfo(environment);            Banner printedBanner = printBanner(environment);            context = createApplicationContext();            exceptionReporters = getSpringFactoriesInstances(                    SpringBootExceptionReporter.class,newClass[] { ConfigurableApplicationContext.class}, context);            prepareContext(context, environment, listeners, applicationArguments,                    printedBanner);            refreshContext(context);            afterRefresh(context, applicationArguments);            stopWatch.stop();if(this.logStartupInfo) {newStartupInfoLogger(this.mainApplicationClass)                        .logStarted(getApplicationLog(), stopWatch);            }            listeners.started(context);            callRunners(context, applicationArguments);        }catch(Throwable ex) {            handleRunFailure(context, ex, exceptionReporters, listeners);thrownewIllegalStateException(ex);        }try{            listeners.running(context);        }catch(Throwable ex) {            handleRunFailure(context, ex, exceptionReporters,null);thrownewIllegalStateException(ex);        }returncontext;    }

我们先来分析其中的第一个关键代码:SpringApplicationRunListeners listeners = getRunListeners(args);

这行代码是获取监听器,我们先跳转到getRunListeners中看一下:

privateSpringApplicationRunListeners getRunListeners(String[] args) {Class[] types =newClass[] { SpringApplication.class, String[].class};returnnewSpringApplicationRunListeners(logger, getSpringFactoriesInstances(                SpringApplicationRunListener.class, types,this, args));    }

在这段代码中,我们看到获取监听器,是new出来了一个SpringApplicationRunListeners实例并返回。

再次跳转到SpringApplicationRunListeners的构造函数中,看到一下发生了什么:

SpringApplicationRunListeners(Loglog,    Collection listeners) {this.log=log;this.listeners =newArrayList(listeners);    }

在这个构造函数里,我们看到其只是把接收到的listeners参数,保存到实例变量里,没有过多的操作。

所以,重点是在listeners参数这里,而listeners是通过getSpringFactoriesInstances创建出来的,来看一下getSpringFactoriesInstances函数做了什么事情吧:

privateCollection getSpringFactoriesInstances(Classtype,Class[] parameterTypes,Object... args) {ClassLoaderclassLoader =Thread.currentThread().getContextClassLoader();// Use names and ensure unique to protect against duplicatesSet names =newLinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));List instances = createSpringFactoriesInstances(type, parameterTypes,classLoader, args, names);AnnotationAwareOrderComparator.sort(instances);returninstances;    }

在这里我们看到,首先创建了一个classloader,然后用SpringFactoriesLoader.loadFactoryNames(type, classLoader),加载了SpringFactoriesLoader列表。我们来看一下loadFactoryNames里面的代码:

publicstaticList loadFactoryNames(Class factoryClass,

    @Nullable ClassLoader classLoader) {        String factoryClassName = factoryClass.getName();return(List)loadSpringFactories(classLoader).getOrDefault(factoryClassName,        Collections.emptyList());    }privatestaticMap> loadSpringFactories(@Nullable ClassLoader classLoader) {        MultiValueMap result = (MultiValueMap)cache.get(classLoader);if(result !=null) {returnresult;        }else{try{                Enumeration ex = classLoader !=null?                classLoader.getResources("META-INF/spring.factories")                :ClassLoader.getSystemResources("META-INF/spring.factories");                LinkedMultiValueMap result1 =newLinkedMultiValueMap();while(ex.hasMoreElements()) {                    URL url = (URL)ex.nextElement();                    UrlResource resource =newUrlResource(url);                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);                    Iterator var6 = properties.entrySet().iterator();while(var6.hasNext()) {                        Entry entry = (Entry)var6.next();ListfactoryClassNames = Arrays.asList(StringUtils                        .commaDelimitedListToStringArray((String)entry.getValue()));                        result1.addAll((String)entry.getKey(), factoryClassNames);                    }                }                cache.put(classLoader, result1);returnresult1;            }catch(IOException var9) {thrownewIllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var9);            }        }    }

通过这里我们看到了其使用了classLoader获取了META-INF/spring.factories这个配置文件下定义的资源。

小发现:在这里我们发现spring boot自动装配文件的位置。

获取到META-INF/spring.factories这个配置文件下的资源名称列表以后,通过createSpringFactoriesInstances函数创建了SpringFactories的实例。

private List createSpringFactoriesInstances(Classtype, Class[] parameterTypes,    ClassLoader classLoader,Object[] args, Set names) {        ArrayList instances =newArrayList(names.size());        Iterator var7 = names.iterator();while(var7.hasNext()) {Stringname = (String)var7.next();try{                Class ex = ClassUtils.forName(name, classLoader);                Assert.isAssignable(type, ex);                Constructorconstructor= ex.getDeclaredConstructor(parameterTypes);                Object instance = BeanUtils.instantiateClass(constructor, args);                instances.add(instance);            } catch (Throwable var12) {thrownewIllegalArgumentException("Cannot instantiate "+type+" : "+ name,                var12);            }        }returninstances;    }

通过上面的这些代码流转,我们大概搞清楚了listeners是怎么创建出来的。

然后调用了listeners的starting方法。我们先大概地看一下EventPublishingRunListener里面的starting的实现:

public void starting() {this.initialMulticaster.multicastEvent(newApplicationStartingEvent(this.application,this.args));    }

关键代码在这里:

public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {        ResolvableType type = eventType !=null?eventType:this.resolveDefaultEventType(event);        Iterator var4 =this.getApplicationListeners(event, type).iterator();while(var4.hasNext()) {            ApplicationListener listener = (ApplicationListener)var4.next();            Executor executor =this.getTaskExecutor();if(executor !=null) {                executor.execute(() -> {this.invokeListener(listener,event);                });            }else{this.invokeListener(listener,event);            }        }    }protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {        ErrorHandler errorHandler =this.getErrorHandler();if(errorHandler !=null) {try{this.doInvokeListener(listener,event);            }catch(Throwable var5) {                errorHandler.handleError(var5);            }        }else{this.doInvokeListener(listener,event);        }    }

在上面代码中我们看到,starting就是拿到META-INF/spring.factories中定义的资源的实例以后,然后再创建一个线程去启动起来。

通过上面的这些代码我们知道了spring boot会获取META-INF/spring.factories中的资源,并创建这些资源的实例(listeners监听器),然后为每一个监听器创建一个线程启动起来。

篇幅有限, 今天就写到这里吧。有希望一起学习spring boot 2.0源码的同学可以关注我,跟我一起分析spring boot 2.0 源码的实现方式。

在此我向大家推荐一个架构学习交流QQ群:725633148 里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多!

原文出处:https://www.cnblogs.com/lizongshen/p/9130740.html

你可能感兴趣的:(spring boot 2.0 源码分析(二))