今日份学习之Spring Boot自动配置实现原理
通过前面章节的学习,我们掌握了使用Spring Boot框架进行实际应用开发的方法。在使用Spring Boot 的过程中,我们时常会为一些看似简单,但实际上蕴藏了强大功能的实现而惊呼,下面就让我们来揭开它的神秘面纱,做到知其然,进而知其所以然。在认识Spring Boot 的实现原理之后,我们在使用某些功能时,就能够做到心中有数,从而更好地使用它。
1 Spring Boot主程序的功能
代码清单10-1是Spring Boot应用的一个典型主程序,它看起来非常简单,使用了一个同样看起来非常简单的注解@SpringBootApplication,并用一个非常普通的main方法运行SpringApplication的 run方法。这个简单的主程序将会加载一个应用所需的所有资源和配置,最后启动一个应用实例。
代码清单10-1Spring Boot应用主程序
今日份学习之Spring Boot自动配置实现原理1.1SpringApplication的run方法
Spring Boot的主程序有什么神奇的地方呢?可以从 SpringApplication的run方法说起,这是应用主程序开始运行的方法,它的源代码如代码清单10-2所示。这个方法让我们能够看清楚Spring Boot的一切秘密所在,它首先开启一个SpringApplicationRun-Listeners监听器,然后创建一个应用上下文ConfigurableApplicationContext,通过这个上下文加载应用所需的类和各种环境配置等,最后启动一个应用实例。
代码清单10-2SpringApplication中run的源代码
今日份学习之Spring Boot自动配置实现原理如果你使用过Spring框架,就会更加清楚这种加载应用的实现机制。在Spring 中,
加载一个应用,主要是通过一些复杂的配置来实现的。这样看来,Spring Boot 只不过是把这些本来由程序员做的工作,事先帮我们实现罢了。
1.2创建应用上下文
一个应用能够正常运行起来,需要一些环境变量、各种资源和一些相关配置等,从创建应用上下文ConfigurableApplicationContext的源代码中,我们可以看到这种实现机制,如代码清单10-3所示。其中,this.load (context, sources.toArray (new Object[sources.size(]))将调用BeanDefinitionLoader来加载应用定义的和需要的类及各种资源。
代码清单10-3创建应用上下文——createAndRefreshContext的源代码
今日份学习之Spring Boot自动配置实现原理 今日份学习之Spring Boot自动配置实现原理1.3自动加载
在BeanDefinitionLoader 中,有一个load (Class<?> source)方法用来加载类定义,如代码清单10-4所示。这里的source就是代码清单10-1中定义的Application.class。在程序中通过isComponent检查是否存在注解,如果有注解,则调用注解相关的类定义。这样注解@SpringBootApplication将被调用,它不但会导入一系列自动配置的类,还会加载应用中一些自定义的类。
代码清单10-4BeanDefinitionLoader 中 load(Class<?>source)源代码
今日份学习之Spring Boot自动配置实现原理 今日份学习之Spring Boot自动配置实现原理从以上分析可知,一个简单的Spring Boot主程序,通过运行一个run方法,就将引发一系列复杂的内部调用和加载过程,从而初始化一个应用所需的配置、环境、资源及各种类定义等。特别是导入了一系列自动配置类,实现了强大的自动配置功能,这是Spring Boot框架最引人注目的地方。
2.Spring Boot自动配置原理
所有的自动配置都是从注解@SpringBootApplication引人的,我们来看看它的源代码,就一切都明白了。如代码清单10-5所示,注解@SpringBootApplication其实又包含了三个非常重要的注解,即@Configuration、@EnableAutoConfiguration和@ComponentScan,其中注解@EnableAutoConfiguration就是启用自动配置的,并将导入一些自动配置的类定义,注解@ComponentScan将扫描和加载应用中的一些自定义的类。
代码清单10-5SpringBootApplication源代码
今日份学习之Spring Boot自动配置实现原理2.1自动配置的即插即用原理
EnableAutoConfiguration最终会导入一个自动配置的类列表,如代码清单10-6所示。列表中的自动配置类很多,这些配置类中大都将被导入,并处于备用状态中,这如同电器中准备了一些插槽一样,即实现了即插即用的原理。这样,当项目中引入了相关的包时,相关的功能将被启用。例如在项目的Maven管理中配置了Redis 的引用,那么Redis的功能将被启用,这时启动应用,程序将尝试读取有关Redis的配置信息。
代码清单10-6自动配置类部分列表
今日份学习之Spring Boot自动配置实现原理2.2自动配置的约定优先原理
在自动配置中加载一个类的配置时,首先读取项目中的配置,只有项目中没有相关配置才启用配置的默认值,这就是自动配置的约定优先原理。代码清单10-7是Thymeleaf配置类的源代码,如果在项目的配置文件中没有配置spring.thymeleaf的相关参数,就使用Thymeleaf 的默认配置,默认配置将使用templates作为HTML文件的存放路径。在前面章节使用Thymeleaf的实例中,就是使用了这个默认配置。
代码清单10-7Thymeleaf 配置源代码
今日份学习之Spring Boot自动配置实现原理3.提升应用的性能
Spring Boot 的自动配置在给我们提供很大便利的同时,难免会有一些副作用,即增加了应用启动的时间、一些内存和CPU的消耗等。如果应用对性能要求很高,就可以根据自动配置的原理,使用一些技巧进行优化。
3.1更改加载配置的方式
如果能清楚一个应用需要哪些配置,就能够更改加载配置的方式,即不使用自动配置,而是改为指定加载一些应用所需的配置。
为了弄清楚一个应用需要加载哪些配置,可以使用Maven调试的方式来启动一个应用,然后从控制台的输出日志中,确定哪些是这个应用需要加载的配置类。下面使用第1章中简单的实例项目来说明这种操作。
首先,在IDEA的Edit Configuration中增加一个Maven配置,工作路径选择项目根目录,在命令行中输入: spring-boot:run -Ddebug,并把配置保存为debug,如图10-1所示。
今日份学习之Spring Boot自动配置实现原理以 Debug方式运行debug配置,启动应用,然后在控制台中找出Positive matches的类,如代码清单10-8所示。Positive matches就是这个应用所需加载的一些配置类。
代码清单10-8加载自动配置的Positive matches类列表
今日份学习之Spring Boot自动配置实现原理通过整理后,得出这个应用需要加载的配置类列表,如代码清单10-9所示。
代码清单10-9整理后的Positive matches类列表
今日份学习之Spring Boot自动配置实现原理根据这个配置类加载列表,就可以在主程序中使用注解@Configuration来代替注解@SpringBootApplication,并用注解@Import 指定需要加载的配置类,经过更改后的应用主程序如代码清单10-10所示。
代码清单10-10主程序中指定加载的配置类
今日份学习之Spring Boot自动配置实现原理3.2将Tomcat换成Jetty
另外,为了提高应用的性能,还可以更改默认使用的Tomcat插件,换成更加小巧的Jetty插件。例如,代码清单10-11是在工程的Maven配置中排除引用默认的Tomcat,转而引用Jetty的依赖。
代码清单10-11使用Jetty的 Maven配置
今日份学习之Spring Boot自动配置实现原理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所示。
今日份学习之Spring Boot自动配置实现原理对比改造前后的两种情况,改造后应用的启动时间有所加快。改造前启动应用的时间如下所示:
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的占用也有所改善,加载的类减少了一点,并不是很明显。从总体上来说,性能是有所改善了。
今日份学习之Spring Boot自动配置实现原理 今日份学习之Spring Boot自动配置实现原理5.小结
本章分析了Spring Boot应用主程序的内部实现的一些源代码,及其功能强大的自动配置的实现原理,使我们认识了神奇的Spring Boot 的内部实现机制,在看似简单的调用中,其实包含着复杂的内部实现。这就不难理解,为什么使用Spring Boot可以那么简单,这是因为它把一些复杂的实现,都事先帮我们做好了。
基于对Spring Boot 的深入了解,特别是认识自动配置的实现原理之后,就可以改造一个应用加载配置的方式,从而达到提高性能的目的。虽然这种改造的作用并不是特别明显,但是不管怎样,至少能帮助我们加深对Spring Boot的理解。
通过前面章节的应用实例,我们也知道,在 Spring Boot中使用数据库也是非常简单的,那么Spring Boot在使用数据库方面,其内部实现又是怎样一个引人入胜的工程呢?下一章将分析Spring Boot在使用数据库方面的一些实现原理,看看它又有什么神奇之处。