springboot2.x初探(三)

这篇文章接着 springboot2.x初探(二)

下面看第九步,准备运行环境

上面第八步准备好的参数在这里用上了,看看这个方法:

springboot2.x初探(三)_第1张图片

先看获取环境的方法:

springboot2.x初探(三)_第2张图片

通过debug可以知道我这里的应用是 SERVLET类型,所以创建的是 StandardServletEnvironment。

然后看配置环境的方法:

springboot2.x初探(三)_第3张图片

可以看到它就是一个模版方法,是为了有顺序地调用configurePropertySources方法和configProfiles方法。

springboot2.x初探(三)_第4张图片

这个方法的第一行代码就带来了疑问,这个environment了里面的propertysources是从哪里来的?

我们再回过头来看看获取环境的地方:

springboot2.x初探(三)_第5张图片

看看这个new的过程中都经历了什么:

在这个StandardServletEnvironment类中没有发现无参构造函数,它会去调用父类StandardEnvironment的无参构造函数,可是在StandardEnvironment中也没有无参构造函数,继续向上找,发现它的父类AbstractEnvironment中有一个无参构造函数:

springboot2.x初探(三)_第6张图片

这个构造函数中调用了一个customizePropertySources方法,这个方法在StandardServletEnvironment类中被重写了:

springboot2.x初探(三)_第7张图片

它还调用了父类的这个方法:

springboot2.x初探(三)_第8张图片

其中的addLast方法:

springboot2.x初探(三)_第9张图片

就是设置propertySource列表

到这里也就知道了这些propertySources其实在创建环境的时候就已经设置好了,所以这里

springboot2.x初探(三)_第10张图片

直接获取没啥毛病。

这里看一下sources都有啥:

springboot2.x初探(三)_第11张图片

有四个,两个servletConfigInitParams,两个systemEnvironment

我们看看这两个systemEnvironment都有啥:

springboot2.x初探(三)_第12张图片

springboot2.x初探(三)_第13张图片

springboot2.x初探(三)_第14张图片

springboot2.x初探(三)_第15张图片

springboot2.x初探(三)_第16张图片

springboot2.x初探(三)_第17张图片

看到这些信息我真是瑟瑟发抖~~~

所有我电脑的信息,配置的环境变量,jvm的信息,jdk的信息一览无余!

接着看configureProfiles方法吧:

springboot2.x初探(三)_第18张图片

springboot2.x初探(三)_第19张图片

springboot2.x初探(三)_第20张图片

springboot2.x初探(三)_第21张图片

程序运行到这里,经过debug验证,因为我在application.properties中没有配置 spring.profiles.active,所以获取到的activeProfiles是空的。

下面继续看配置监听器的环境:

springboot2.x初探(三)_第22张图片

可以看到实际上调用了listener自己的environmentPrepared方法,

springboot2.x初探(三)_第23张图片

这个方法中的代码是不是很眼熟?

原来它跟starting方法中的调用特别像

springboot2.x初探(三)_第24张图片

只不过广播的事件类型从startingEvent改为了environmentpreparedEvent。我们看到ApplicationEnvironmentPreparedEvent构造函数中传入了三个参数,除了application,args之外还多了environment,我们看看这个构造函数:

springboot2.x初探(三)_第25张图片

显式调用了父类的构造函数:

springboot2.x初探(三)_第26张图片

又显式调用了父类的构造函数:

springboot2.x初探(三)_第27张图片

继续看:

springboot2.x初探(三)_第28张图片

像这样每个字类都多个字段的设计是什么设计模式来着?(下面再看吧,这里先继续往下看)

接下来调用multicastEvent方法的过程就和starting方法时是一样样的了,这里就不看了。

看到这里我们就知道这个 listeners.environmentPrepared(environment);方法实际上是对preparedEvent事件的广播。

下面继续看bindToSpringApplication(environment);

springboot2.x初探(三)_第29张图片

这个Binder是什么呢?看源码和注释

springboot2.x初探(三)_第30张图片

它就是一个容器类,用来绑定多个对象。在这个类加载的时候,有个静态代码块同时执行了,它添加了一个 JavaBeanBinder,然后将他放到一个list中并赋值给了一个不可变的list属性。

接下来看它的get方法:

springboot2.x初探(三)_第31张图片

从注释看它是从给定的环境中创建一个Binder,其中的两个参数调用了两个方法,我们先看第一个方法:

springboot2.x初探(三)_第32张图片

它返回了一个先前附加到environment上的 ConfigurationPropertySource实例集合,我们来逐行分析代码:

这行代码返回了之前创建环境的时候设置的propertySources:

springboot2.x初探(三)_第33张图片

springboot2.x初探(三)_第34张图片

springboot2.x初探(三)_第35张图片

springboot2.x初探(三)_第36张图片

返回一个为了进行比较的PropertySource接口实现类实例。注释中还给出了用法,正是跟我们现在分析的代码一样的。

springboot2.x初探(三)_第37张图片

我们看这个ComparisonPropertySource就是专门用来做比较用的。它是一个内部类,并且继承了StubPropertySource,这个StubPropertySource类又是做什么的呢?

springboot2.x初探(三)_第38张图片

从它的注释知道它就是一个占位符,是一个当应用上下文创建过程中一个实际的property source的占位符。

上面我们看到named方法中调用了ComparisonPropertySource的构造函数,然后它又调用了StubPropertySource类的构造函数,从上面的截图中我们可以看到StubPropertySource的构造函数也就只是调用了它父类的构造函数:

springboot2.x初探(三)_第39张图片

没有什么其他的操作。

所以这个方法:

springboot2.x初探(三)_第40张图片

实际就是获取configurationProperties的PropertySource。然后做了强制转换:

springboot2.x初探(三)_第41张图片

然后判断获取到的值是否为null,若为空则调用from方法,若不为空则返回它的source。

我们看看from方法:

springboot2.x初探(三)_第42张图片

从上面的代码截图可以发现就是用了一个适配器将 MutablePropertySources转换为了ConfigurationPropertySource。

下面看第二个参数:

springboot2.x初探(三)_第43张图片

可以看到它就是一个占位符解析器。

springboot2.x初探(三)_第44张图片

这个方法是获取环境中的PropertySources。

springboot2.x初探(三)_第45张图片

这个有两个参数的构造函数中,第一个参数通过上面截图中的getSources方法获取,另一个参数为null,从构造函数总看到当helper为空的时候new了一个,这个PropertyPlaceholderHelper是什么呢?

springboot2.x初探(三)_第46张图片

处理有占位符的字符串的公共类。

springboot2.x初探(三)_第47张图片

springboot2.x初探(三)_第48张图片

springboot2.x初探(三)_第49张图片

可以看到在加载PropertyPlaceholderHelper的时候会在wellKnownSimplePrefixes中添加三种常见的 前后缀,然后在构造函数中会对传入的后缀进行判断,下面继续看Binder的构造函数:

springboot2.x初探(三)_第50张图片

从下面这一句可以知道调用了ApplicationConversionService.getSharedInstance方法:

springboot2.x初探(三)_第51张图片

从上面这个方法可以知道是用单例模式创建了一个ApplicationConversionService的实例。

springboot2.x初探(三)_第52张图片

springboot2.x初探(三)_第53张图片

我们看到这个方法的参数是FormatterRegistry类型,但是上面传递的却是 this关键字,我们看看这个类是否继承或实现了FormatterRegistry:

果然它的父类实现了这个接口类,在跟代码的过程中我们发现ApplicationConversionService类的两个父类都没有显式地实现无参构造函数,所以我们只看当前类的构造函数就可以。

springboot2.x初探(三)_第54张图片

先看看第一个 addScalaConverters方法:

springboot2.x初探(三)_第55张图片

springboot2.x初探(三)_第56张图片

这个方法中给ApplicationConversionService类添加了这么多转换器。我们看第一个:

springboot2.x初探(三)_第57张图片

springboot2.x初探(三)_第58张图片

springboot2.x初探(三)_第59张图片

下面的 1处我们已经看过了,我们看 2 处的代码

springboot2.x初探(三)_第60张图片

springboot2.x初探(三)_第61张图片

springboot2.x初探(三)_第62张图片

这里使用的是递归调用,最终返回一个ResolvableType,接着看方法中的第二行代码:

springboot2.x初探(三)_第63张图片

返回一个代表一般的参数的ResolvableType数组。具体的方法内容这里就不做分析了,下面有时间了再仔细看。

所以

springboot2.x初探(三)_第64张图片

方法中的typeInfo就是代表一般的参数的ResolvableType数组。

springboot2.x初探(三)_第65张图片

其他的增加转换器的过程就不再看了。下面继续看

springboot2.x初探(三)_第66张图片

上面是增加的转换器,下面的是格式注册:

springboot2.x初探(三)_第67张图片

springboot2.x初探(三)_第68张图片

然后是:

springboot2.x初探(三)_第69张图片

springboot2.x初探(三)_第70张图片

上面这一块就先到这吧,先不进行更深度的分析了,我们继续往下走上面看了那么多,其实我们才看到这里:

springboot2.x初探(三)_第71张图片

还有这里:

springboot2.x初探(三)_第72张图片

接下来我们看这里:

springboot2.x初探(三)_第73张图片

具体的bind,前面的get部分我们基本上看完了,下面看bind部分:

springboot2.x初探(三)_第74张图片

两个参数:name和Bindable的泛型,我们上面传递的是什么参数呢?

一个是"spring.main",一个是一个方法,我们看看后面第二个参数:

springboot2.x初探(三)_第75张图片

用一个等于现有实例的值创建一个指定实例的新的可绑定项。(我也不知道这是什么意思,只是翻译注释,等后面再仔细理解。)

下面继续看bind方法:

springboot2.x初探(三)_第76张图片

由于上面传入的handler是null所以这里会调用BindHandler.DEFAULT,我们看看这个:

springboot2.x初探(三)_第77张图片

同时在这个接口中我还发现了一些方法实体!!!

springboot2.x初探(三)_第78张图片

在我原来的认知中,接口中是不能 有方法实体的,那这里为什么可以这么写呢?

原来从jdk1.8之后接口中也可以有方法实体了,这样似乎更符合面向对象特性,不过方法前要加上 default修饰。这样的方法是可以直接在子类中调用的。

到这里我们先看到BindResult.of(bound)。其他的详细细节先不看了,内容太多了,并且现在没什么心情看了。

springboot2.x初探(三)_第79张图片

bindToSpringApplication方法我们就先看到这里,接着看下面的判断代码块。

对于这里的判断,我们已经知道我们的应用是SERVLET类型的所以不会走这块代码,直接往下看attach方法:

springboot2.x初探(三)_第80张图片

springboot2.x初探(三)_第81张图片

这段代码的主要作用就是将 name为 configurationProperties的PropertySource放到列表中第一个。

到这里run方法中的第九步就基本看完了,当然还有很多细节没有看,那些不是现在这篇文章要分析的,我们先继续看第十步:

springboot2.x初探(三)_第82张图片

我们看具体的方法实现:

springboot2.x初探(三)_第83张图片

经过分析可以看到,这个方法就是将系统属性中的 spring.beaninfo.ignore设置为true。它的作用是跳过搜索BeanInfo类。具体究竟是怎么起作用的呢,我还不知道,后面遇到再分析。

后面内容还多,将在下面的文章中继续分析。

你可能感兴趣的:(学习之路)