spring-boot-autoconfigure

╰半夏微凉° 2022-03-26 08:56 229阅读 0赞
  1. 初次接触spring-boot的时候,我们经常会看到这样的文章:“为什么要使用spring-boot "spring-boot与spring mvc有什么区别",在这些文章中几乎都会出现这样的一句话“约定优于配置”,确实是这样的,spring-bootspring-mvc的一个重要区别就是spring-boot遵循“约定优于配置”这一原则,而spring-boot-autoconfigure模块正是完美的实现这个原则,所以我们今天就来说一说spring-boot-autoconfigure这个模块。
  2. 顾名思义,autoconfigure就是自动配置的意思,我们先看一个比较常用的例子,我们都知道,对于90%的web项目我们都需要使用数据库(比如mysql),所以就需要用到datasource,我们就先以datasource的自动配置为例吧。
  3. 使用过spring-boot的都知道,我们只需要在application.yml中进行以下配置即可在应用中使用对应的数据库连接
  4. spring:
  5. datasource:
  6. driver-class-name: com.mysql.jdbc.Driver
  7. url: "jdbc:mysql://127.0.0.1/crs_db?useUnicode=true&characterEncoding=utf"
  8. username: root
  9. password: 123456
  10. 对于习惯了spring-mvc的同学来说,这真是太简洁了!我们下面来看一下spring-boot-autoconfigure是怎样简化这些步骤的,话不多说,直奔关键代码: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
  11. @Configuration // 备注1
  12. @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class }) //备注2
  13. @EnableConfigurationProperties(DataSourceProperties.class) //备注3
  14. @Import({ DataSourcePoolMetadataProvidersConfiguration.class,
  15. DataSourceInitializationConfiguration.class }) //备注4
  16. public class DataSourceAutoConfiguration {
  17. // 这里是为了开启一个内嵌的datasource,因为不满足某些条件,因此最终不会实例化一个dataSource
  18. @Configuration
  19. @Conditional(EmbeddedDatabaseCondition.class)
  20. @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
  21. @Import(EmbeddedDataSourceConfiguration.class)
  22. protected static class EmbeddedDatabaseConfiguration {
  23. }
  24. @Configuration
  25. @Conditional(PooledDataSourceCondition.class)
  26. // 由于上面的EmbeddedDatabase没有实例化成功,所以在这里还没有dataSource,所以还可以往下玩
  27. @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
  28. @Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
  29. DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class,
  30. DataSourceJmxConfiguration.class }) // 备注5
  31. protected static class PooledDataSourceConfiguration {
  32. }
  33. // 其它代码省略
  34. 备注1 @Configuration 这个注解我就不解释了,用过spring-boot的都知道是干啥的
  35. 备注2: @ConditionalOnClass表示只有classpath中能找到DataSource.classEmbeddedDatabaseType.class时,DataSourceAutoConfiguration这个类才会被spring容器实例化,这其实也解释了为什么我们有时候只需要在pom.xml添加某些依赖包,某些功能就自动打开了,就是这个注解干的好事儿。
  36. 备注3 @EnableConfigurationProperties引入了DataSourceProperties的配置,简单看一下代码,是不是有一种似曾相识的感觉, spring.datasource.url这些不就是application.yml中的配置吗,所以从这里我们就知道我们的配置是用在这里的。
  37. @ConfigurationProperties(prefix = "spring.datasource")
  38. public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {
  39. private ClassLoader classLoader;
  40. private String name;
  41. private boolean generateUniqueName;
  42. private Class<? extends DataSource> type;
  43. private String driverClassName;
  44. private String url;
  45. private String username;
  46. private String password;
  47. private String jndiName;
  48. private DataSourceInitializationMode initializationMode = DataSourceInitializationMode.EMBEDDED;
  49. private String platform = "all";
  50. private List<String> schema;
  51. private String schemaUsername;
  52. private String schemaPassword;
  53. private List<String> data;
  54. private String dataUsername;
  55. private String dataPassword;
  56. private boolean continueOnError = false;
  57. private String separator = ";";
  58. private Charset sqlScriptEncoding;
  59. 备注4 使用了 @Import注解引入了DataSourcePoolMetadataProvidersConfiguration DataSourceInitializationConfiguration,这里我们重点关注一下DataSourceInitializationConfiguration
  60. @Configuration
  61. public class DataSourcePoolMetadataProvidersConfiguration {
  62. // tomcat自带的datasource连接池,由于默认情况下spring-boot未引入org.apache.tomcat.jdbc.pool.DataSource对应的依赖包,
  63. // 根据@ConditionalOnClass注解的作用,这个配置不会生效
  64. @Configuration
  65. @ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
  66. static class TomcatDataSourcePoolMetadataProviderConfiguration {
  67. @Bean
  68. public DataSourcePoolMetadataProvider tomcatPoolDataSourceMetadataProvider() {
  69. return (dataSource) -> {
  70. if (dataSource instanceof org.apache.tomcat.jdbc.pool.DataSource) {
  71. return new TomcatDataSourcePoolMetadata(
  72. (org.apache.tomcat.jdbc.pool.DataSource) dataSource);
  73. }
  74. return null;
  75. };
  76. }
  77. }
  78. // hikaricp是spring-boot默认的连接池(据说速度超快),HikariDataSource的包默认在spring-boot的全家桶中,
  79. //所以最终会实例化DataSourcePoolMetadataProvider 的一个bean
  80. @Configuration
  81. @ConditionalOnClass(HikariDataSource.class)
  82. static class HikariPoolDataSourceMetadataProviderConfiguration {
  83. @Bean
  84. public DataSourcePoolMetadataProvider hikariPoolDataSourceMetadataProvider() {
  85. return (dataSource) -> {
  86. if (dataSource instanceof HikariDataSource) {
  87. return new HikariDataSourcePoolMetadata(
  88. (HikariDataSource) dataSource);
  89. }
  90. return null;
  91. };
  92. }
  93. }
  94. // dbcp2连接池的配置,很不幸,BasicDataSource不在默认包中,所以这个连接池不会生效
  95. @Configuration
  96. @ConditionalOnClass(BasicDataSource.class)
  97. static class CommonsDbcp2PoolDataSourceMetadataProviderConfiguration {
  98. @Bean
  99. public DataSourcePoolMetadataProvider commonsDbcp2PoolDataSourceMetadataProvider() {
  100. return (dataSource) -> {
  101. if (dataSource instanceof BasicDataSource) {
  102. return new CommonsDbcp2DataSourcePoolMetadata(
  103. (BasicDataSource) dataSource);
  104. }
  105. return null;
  106. };
  107. }
  108. }
  109. }
  110. 从上面的代码可以知道spring-boot默认实现了hikari连接池。
  111. 备注5 @Import引入了DataSourceConfiguration的几个内部类(HikariTomcatDbcp2Generic) ,上面我们也说了Hikari是亲儿子,所以TomcatDbcp2肯定是死在了@ConditionalOnClass上了,所以我们只看HikariGeneric
  112. abstract class DataSourceConfiguration {
  113. //HikariDataSource肯定存在,往下走
  114. @ConditionalOnClass(HikariDataSource.class)
  115. // 在此之前还没有实例化DataSource,往下走(如果我们在应用中主动实现了datasource,那默认的hikari就不会实现,
  116. //这个也很常见,比如我们使用阿里巴巴的durid连接池,也是基于类似的原理,当然比这要稍微复杂些)
  117. @ConditionalOnMissingBean(DataSource.class)
  118. // 当配置 spring.datasource.type=com.zaxxer.hikari.HikariDataSource或该配置不存在时,往下走
  119. @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true)
  120. static class Hikari {
  121. // 若以上4个注解的条件都满足,则在这里实例化一个HikariDataSource的bean,很显然它也是DataSource的子类
  122. @Bean
  123. @ConfigurationProperties(prefix = "spring.datasource.hikari")
  124. public HikariDataSource dataSource(DataSourceProperties properties) {
  125. HikariDataSource dataSource = createDataSource(properties,
  126. HikariDataSource.class);
  127. if (StringUtils.hasText(properties.getName())) {
  128. dataSource.setPoolName(properties.getName());
  129. }
  130. return dataSource;
  131. }
  132. }
  133. // 若DataSource没有bean存在,则往下走,很不幸,在上面已经实例化过HikariDataSource,止步于此,
  134. // 看去来这只是为了避免之前都没有实例化dataSource,这里来默认一个dataSource
  135. @ConditionalOnMissingBean(DataSource.class)
  136. @ConditionalOnProperty(name = "spring.datasource.type")
  137. static class Generic {
  138. @Bean
  139. public DataSource dataSource(DataSourceProperties properties) {
  140. return properties.initializeDataSourceBuilder().build();
  141. }
  142. }
  143. 至此,数据源和连接池都已实例化完成。讲解的非常粗糙,但是这不重要,因为我们今天的主角可不是dataSource,别忘了我们要讲的是spring-boot-autoconfigure,通过上面的例子,其实最关键的是几个注解
  144. **@ConditionalOnClass : **当对应的类存在时则表示满足条件,一个典型的例子,spring-boot中经常会在你添加了某一个模块的maven依赖之后,该功能就自动开启了,比如添加org.flywaydb.flyway-core的依赖包后会默认开启flyway
  145. **@Import : ** 类似于spring-mvcimport标签
  146. **@ConditionalOnMissingBean: ** 当对应的beanbeanFactory不存在时表示满足条件,一般用于只允许类的一个bean存在

@ConditionalOnBean: 与ConditionalOnMissingBean的作用相反,一般用于依赖的bean存在时才会实例化

  1. **@ConditionalOnProperty: ** 当对应的属性值为指定值时表示满足条件
  2. 因此我们在接触到一个新的模块后,如果spring-boot会自动配置它,那么我们可以在spring-boot-autoconfigure模块下找到对应的包,然后找到以AutoConfiguration结尾的类,比如flywayFlywayAutoConfiguration,cassandraCassandraAutoConfiguration等等,然后再配合上面的几个注解,就能很快了解新模块的加载过程。
  3. 有些爱思考的同学就要问了,你怎么知道要去找以AutoConfiguration结尾的类,这个就引入了另一个话题,spring-boot是如何实现自动配置的,它怎么知道需要加载哪些AutoConfiguration,这个其实是用到了spring-factories机制,关于spring-factories的详细原理需要单独写一篇文章来介绍,这里只是简单说一下它在autoconfigure中的应用,我们直接来看一下spring-boot-autoconfigure-2.0.6.RELEASE.jar包下的spring.factories文件

20190117105857485.png

里面有这样的一部分配置(如下),key是org.springframework.boot.autoconfigure.EnableAutoConfiguration,value是各个以逗号隔开的*AutoConfiguration,结合spring-factories的运行原理,我们就可以知道所有的自动配置是从这里开始加载的。

  1. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  2. org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
  3. org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
  4. org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
  5. org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
  6. org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
  7. org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
  8. org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
  9. org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
  10. org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
  11. org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
  12. org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
  13. org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
  14. org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
  15. org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
  16. org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
  17. org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
  18. org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
  19. org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
  20. org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
  21. org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
  22. org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
  23. org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
  24. org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
  25. org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
  26. org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\
  27. org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
  28. org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
  29. org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
  30. org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
  31. org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
  32. org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
  33. org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
  34. org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
  35. org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
  36. org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\
  37. org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
  38. org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
  39. org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
  40. org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\
  41. org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
  42. org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
  43. org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
  44. org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
  45. org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
  46. org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
  47. org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
  48. org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\
  49. org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
  50. org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\
  51. org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
  52. org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
  53. org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
  54. org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
  55. org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
  56. org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
  57. org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
  58. org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
  59. org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
  60. org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
  61. org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
  62. org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
  63. org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
  64. org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
  65. org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
  66. org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
  67. org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
  68. org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
  69. org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
  70. org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
  71. org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
  72. org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
  73. org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
  74. org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
  75. org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
  76. org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
  77. org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
  78. org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
  79. org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
  80. org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\
  81. org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
  82. org.springframework.boot.autoconfigure.security.servlet.SecurityRequestMatcherProviderAutoConfiguration,\
  83. org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
  84. org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
  85. org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
  86. org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
  87. org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
  88. org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
  89. org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration,\
  90. org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
  91. org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
  92. org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
  93. org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
  94. org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
  95. org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\
  96. org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
  97. org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
  98. org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
  99. org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
  100. org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
  101. org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
  102. org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
  103. org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
  104. org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
  105. org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
  106. org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
  107. org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
  108. org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
  109. org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
  110. org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
  111. org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration
  112. 知道了原理后,我们也可以自己定义自己的自动配置模块,只需要在自己的jar包下添加 MATA-INF/spring.factories文件,然后加上配置org.springframework.boot.autoconfigure.EnableAutoConfiguration=\[我们自己写的autoconfigure\],举个常用的例子,上面我们提到了阿里巴巴的durid数据库连接池,durid也专门提供了自动配置支持

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NvbmdfamF2YQ_size_16_color_FFFFFF_t_70

  1. 其中spring.factories中的内容是这样的
  2. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  3. com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
  4. DruidDataSourceAutoConfigure.java中的内容如下,跟我们之前介绍的dataSource的例子差不多,都是使用了几个常用的注解来实现自动配置。![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NvbmdfamF2YQ_size_16_color_FFFFFF_t_70 1][]
  5. 总结一下,spring-boot通过spring-boot-autoconfigure体现了"约定优于配置"这一设计原则,而spring-boot-autoconfigure主要用到了spring.factories和几个常用的注解条件来实现自动配置,思路很清晰也很简单。
  6. 但是我特别偏爱spring-boot-autoconfigure这个模块,其中一个最大的好处就是,当我在使用一个新的功能或模块时,比如spring内置的flyway,cassandra或是阿里巴巴第三方的durid,我只需要顺着spring-boot-autoconfigure的自动配置,就能大致了解新模块的加载过程以及运行的原理,这对于我们熟悉新的模块确实起到了事半功倍的效果,希望spring-boot-autoconfigure也能给各位带来更好的学习体验。

发表评论

表情:
评论列表 (有 0 条评论,229人围观)

还没有评论,来说两句吧...

相关阅读