在上一章学习了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