12

今日份学习之 Spring Boot 自动配置实现原理

 3 years ago
source link: https://xie.infoq.cn/article/39c1beef963f61cb28fcc3b4e
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

通过前面章节的学习,我们掌握了使用Spring Boot框架进行实际应用开发的方法。在使用Spring Boot 的过程中,我们时常会为一些看似简单,但实际上蕴藏了强大功能的实现而惊呼,下面就让我们来揭开它的神秘面纱,做到知其然,进而知其所以然。在认识Spring Boot 的实现原理之后,我们在使用某些功能时,就能够做到心中有数,从而更好地使用它。

1 Spring Boot主程序的功能

代码清单10-1是Spring Boot应用的一个典型主程序,它看起来非常简单,使用了一个同样看起来非常简单的注解@SpringBootApplication,并用一个非常普通的main方法运行SpringApplication的 run方法。这个简单的主程序将会加载一个应用所需的所有资源和配置,最后启动一个应用实例。

代码清单10-1Spring Boot应用主程序

7RBNnqa.jpg!mobile

1.1SpringApplication的run方法

Spring Boot的主程序有什么神奇的地方呢?可以从 SpringApplication的run方法说起,这是应用主程序开始运行的方法,它的源代码如代码清单10-2所示。这个方法让我们能够看清楚Spring Boot的一切秘密所在,它首先开启一个SpringApplicationRun-Listeners监听器,然后创建一个应用上下文ConfigurableApplicationContext,通过这个上下文加载应用所需的类和各种环境配置等,最后启动一个应用实例。

代码清单10-2SpringApplication中run的源代码

2QN3yey.png!mobile

如果你使用过Spring框架,就会更加清楚这种加载应用的实现机制。在Spring 中,

加载一个应用,主要是通过一些复杂的配置来实现的。这样看来,Spring Boot 只不过是把这些本来由程序员做的工作,事先帮我们实现罢了。

1.2创建应用上下文

一个应用能够正常运行起来,需要一些环境变量、各种资源和一些相关配置等,从创建应用上下文ConfigurableApplicationContext的源代码中,我们可以看到这种实现机制,如代码清单10-3所示。其中,this.load (context, sources.toArray (new Object[sources.size(]))将调用BeanDefinitionLoader来加载应用定义的和需要的类及各种资源。

代码清单10-3创建应用上下文——createAndRefreshContext的源代码

FZjm6zu.png!mobile

Jj6bQfi.png!mobile

1.3自动加载

在BeanDefinitionLoader 中,有一个load (Class<?> source)方法用来加载类定义,如代码清单10-4所示。这里的source就是代码清单10-1中定义的Application.class。在程序中通过isComponent检查是否存在注解,如果有注解,则调用注解相关的类定义。这样注解@SpringBootApplication将被调用,它不但会导入一系列自动配置的类,还会加载应用中一些自定义的类。

代码清单10-4BeanDefinitionLoader 中 load(Class<?>source)源代码

rqiqQbu.png!mobile

yQ7BBza.png!mobile

从以上分析可知,一个简单的Spring Boot主程序,通过运行一个run方法,就将引发一系列复杂的内部调用和加载过程,从而初始化一个应用所需的配置、环境、资源及各种类定义等。特别是导入了一系列自动配置类,实现了强大的自动配置功能,这是Spring Boot框架最引人注目的地方。

2.Spring Boot自动配置原理

所有的自动配置都是从注解@SpringBootApplication引人的,我们来看看它的源代码,就一切都明白了。如代码清单10-5所示,注解@SpringBootApplication其实又包含了三个非常重要的注解,即@Configuration、@EnableAutoConfiguration和@ComponentScan,其中注解@EnableAutoConfiguration就是启用自动配置的,并将导入一些自动配置的类定义,注解@ComponentScan将扫描和加载应用中的一些自定义的类。

代码清单10-5SpringBootApplication源代码

rIZRzeb.jpg!mobile

2.1自动配置的即插即用原理

EnableAutoConfiguration最终会导入一个自动配置的类列表,如代码清单10-6所示。列表中的自动配置类很多,这些配置类中大都将被导入,并处于备用状态中,这如同电器中准备了一些插槽一样,即实现了即插即用的原理。这样,当项目中引入了相关的包时,相关的功能将被启用。例如在项目的Maven管理中配置了Redis 的引用,那么Redis的功能将被启用,这时启动应用,程序将尝试读取有关Redis的配置信息。

代码清单10-6自动配置类部分列表

emUVzmy.png!mobile

2.2自动配置的约定优先原理

在自动配置中加载一个类的配置时,首先读取项目中的配置,只有项目中没有相关配置才启用配置的默认值,这就是自动配置的约定优先原理。代码清单10-7是Thymeleaf配置类的源代码,如果在项目的配置文件中没有配置spring.thymeleaf的相关参数,就使用Thymeleaf 的默认配置,默认配置将使用templates作为HTML文件的存放路径。在前面章节使用Thymeleaf的实例中,就是使用了这个默认配置。

代码清单10-7Thymeleaf 配置源代码

zyMBf2B.png!mobile

3.提升应用的性能

Spring Boot 的自动配置在给我们提供很大便利的同时,难免会有一些副作用,即增加了应用启动的时间、一些内存和CPU的消耗等。如果应用对性能要求很高,就可以根据自动配置的原理,使用一些技巧进行优化。

3.1更改加载配置的方式

如果能清楚一个应用需要哪些配置,就能够更改加载配置的方式,即不使用自动配置,而是改为指定加载一些应用所需的配置。

为了弄清楚一个应用需要加载哪些配置,可以使用Maven调试的方式来启动一个应用,然后从控制台的输出日志中,确定哪些是这个应用需要加载的配置类。下面使用第1章中简单的实例项目来说明这种操作。

首先,在IDEA的Edit Configuration中增加一个Maven配置,工作路径选择项目根目录,在命令行中输入: spring-boot:run -Ddebug,并把配置保存为debug,如图10-1所示。

bm2yueN.png!mobile

以 Debug方式运行debug配置,启动应用,然后在控制台中找出Positive matches的类,如代码清单10-8所示。Positive matches就是这个应用所需加载的一些配置类。

代码清单10-8加载自动配置的Positive matches类列表

jYFN3uQ.png!mobile

通过整理后,得出这个应用需要加载的配置类列表,如代码清单10-9所示。

代码清单10-9整理后的Positive matches类列表

QvEJJfi.png!mobile

根据这个配置类加载列表,就可以在主程序中使用注解@Configuration来代替注解@SpringBootApplication,并用注解@Import 指定需要加载的配置类,经过更改后的应用主程序如代码清单10-10所示。

代码清单10-10主程序中指定加载的配置类

zquQzeB.png!mobile

3.2将Tomcat换成Jetty

另外,为了提高应用的性能,还可以更改默认使用的Tomcat插件,换成更加小巧的Jetty插件。例如,代码清单10-11是在工程的Maven配置中排除引用默认的Tomcat,转而引用Jetty的依赖。

代码清单10-11使用Jetty的 Maven配置

bQz2Qrb.png!mobile

4.性能对照测试

通过上面一些改造之后,可以对照测试一下,看看效果如何。打开IDEA的 EditConfiguration对话框,增加一个Application配置,工作目录选择工程根目录,并选择工程主程序,然后在VM options 中输入如下配置参数:

-Dcom.sun.management.jmxremote -Dcom.sun.management .jmxremote.port="9004"-Dcom.sun. management .jmxremote.authenticate="false"

-Dcom . sun . management . jmxremote.ssl= "false"

这样配置的目的,是让我们可以使用JConsole来观察应用运行的各项性能指标。配置完成后的效果如图10-2所示。

RjqQNf2.png!mobile

对比改造前后的两种情况,改造后应用的启动时间有所加快。改造前启动应用的时间如下所示:

started Application in 3.171 seconds (JVM running for 4.941)

改造后启动应用的时间如下:

started Application in 2.957 seconds (JVM running for 5.869)

应用启动后,使用JConsole新建一个连接,可以观察应用运行的各项性能指标。根据上面配置的参数,可以在远程进程中输入 localhost:9004,然后单击“连接”按钮,如图10-3所示。

改造前后的两种运行情况对照如图10-4所示。图中各项指标处于0的位置是中间停止时的状态,从图中可以看出,改造后内存的使用量明显减少了,CPU的占用也有所改善,加载的类减少了一点,并不是很明显。从总体上来说,性能是有所改善了。

qI7rQr.jpg!mobile

Jvua2qI.png!mobile

5.小结

本章分析了Spring Boot应用主程序的内部实现的一些源代码,及其功能强大的自动配置的实现原理,使我们认识了神奇的Spring Boot 的内部实现机制,在看似简单的调用中,其实包含着复杂的内部实现。这就不难理解,为什么使用Spring Boot可以那么简单,这是因为它把一些复杂的实现,都事先帮我们做好了。

基于对Spring Boot 的深入了解,特别是认识自动配置的实现原理之后,就可以改造一个应用加载配置的方式,从而达到提高性能的目的。虽然这种改造的作用并不是特别明显,但是不管怎样,至少能帮助我们加深对Spring Boot的理解。

通过前面章节的应用实例,我们也知道,在 Spring Boot中使用数据库也是非常简单的,那么Spring Boot在使用数据库方面,其内部实现又是怎样一个引人入胜的工程呢?下一章将分析Spring Boot在使用数据库方面的一些实现原理,看看它又有什么神奇之处。

最后,还给大家整理了一份面试宝典有需要的添加小编的vx:mxzFAFAFA即可免费领取!!!

fiMrqmB.png!mobile

N736jm.png!mobile

NzEryua.png!mobile


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK