spring-boot-autoconfigure模塊用法詳解
初次接觸spring-boot的時候,我們經常會看到這樣的文章:“為什么要使用spring-boot” "spring-boot與spring mvc有什么區(qū)別",在這些文章中幾乎都會出現(xiàn)這樣的一句話“約定優(yōu)于配置”,確實是這樣的,spring-boot與spring-mvc的一個重要區(qū)別就是spring-boot遵循“約定優(yōu)于配置”這一原則,而spring-boot-autoconfigure模塊正是完美的實現(xiàn)這個原則,所以我們今天就來說一說spring-boot-autoconfigure這個模塊。
顧名思義,autoconfigure就是自動配置的意思,我們先看一個比較常用的例子,我們都知道,對于90%的web項目我們都需要使用數(shù)據庫(比如mysql),所以就需要用到datasource,我們就先以datasource的自動配置為例吧。
使用過spring-boot的都知道,我們只需要在application.yml中進行以下配置即可在應用中使用對應的數(shù)據庫連接
spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: "jdbc:mysql://127.0.0.1/crs_db?useUnicode=true&characterEncoding=utf" username: root password: 123456
對于習慣了spring-mvc的同學來說,這真是太簡潔了!我們下面來看一下spring-boot-autoconfigure是怎樣簡化這些步驟的,話不多說,直奔關鍵代碼: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
@Configuration // 備注1 @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class }) //備注2 @EnableConfigurationProperties(DataSourceProperties.class) //備注3 @Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class }) //備注4 public class DataSourceAutoConfiguration { // 這里是為了開啟一個內嵌的datasource,因為不滿足某些條件,因此最終不會實例化一個dataSource @Configuration @Conditional(EmbeddedDatabaseCondition.class) @ConditionalOnMissingBean({ DataSource.class, XADataSource.class }) @Import(EmbeddedDataSourceConfiguration.class) protected static class EmbeddedDatabaseConfiguration { } @Configuration @Conditional(PooledDataSourceCondition.class) // 由于上面的EmbeddedDatabase沒有實例化成功,所以在這里還沒有dataSource,所以還可以往下玩 @ConditionalOnMissingBean({ DataSource.class, XADataSource.class }) @Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class, DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class, DataSourceJmxConfiguration.class }) // 備注5 protected static class PooledDataSourceConfiguration { } // 其它代碼省略
備注1: @Configuration 這個注解我就不解釋了,用過spring-boot的都知道是干啥的
備注2: @ConditionalOnClass表示只有classpath中能找到DataSource.class和EmbeddedDatabaseType.class時,DataSourceAutoConfiguration這個類才會被spring容器實例化,這其實也解釋了為什么我們有時候只需要在pom.xml添加某些依賴包,某些功能就自動打開了,就是這個注解干的好事兒。
備注3: @EnableConfigurationProperties引入了DataSourceProperties的配置,簡單看一下代碼,是不是有一種似曾相識的感覺, spring.datasource.url這些不就是application.yml中的配置嗎,所以從這里我們就知道我們的配置是用在這里的。
@ConfigurationProperties(prefix = "spring.datasource") public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean { private ClassLoader classLoader; private String name; private boolean generateUniqueName; private Class<? extends DataSource> type; private String driverClassName; private String url; private String username; private String password; private String jndiName; private DataSourceInitializationMode initializationMode = DataSourceInitializationMode.EMBEDDED; private String platform = "all"; private List<String> schema; private String schemaUsername; private String schemaPassword; private List<String> data; private String dataUsername; private String dataPassword; private boolean continueOnError = false; private String separator = ";"; private Charset sqlScriptEncoding;
備注4: 使用了 @Import注解引入了DataSourcePoolMetadataProvidersConfiguration 和DataSourceInitializationConfiguration,這里我們重點關注一下DataSourceInitializationConfiguration
@Configuration public class DataSourcePoolMetadataProvidersConfiguration { // tomcat自帶的datasource連接池,由于默認情況下spring-boot未引入org.apache.tomcat.jdbc.pool.DataSource對應的依賴包, // 根據@ConditionalOnClass注解的作用,這個配置不會生效 @Configuration @ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class) static class TomcatDataSourcePoolMetadataProviderConfiguration { @Bean public DataSourcePoolMetadataProvider tomcatPoolDataSourceMetadataProvider() { return (dataSource) -> { if (dataSource instanceof org.apache.tomcat.jdbc.pool.DataSource) { return new TomcatDataSourcePoolMetadata( (org.apache.tomcat.jdbc.pool.DataSource) dataSource); } return null; }; } } // hikaricp是spring-boot默認的連接池(據說速度超快),HikariDataSource的包默認在spring-boot的全家桶中, //所以最終會實例化DataSourcePoolMetadataProvider 的一個bean @Configuration @ConditionalOnClass(HikariDataSource.class) static class HikariPoolDataSourceMetadataProviderConfiguration { @Bean public DataSourcePoolMetadataProvider hikariPoolDataSourceMetadataProvider() { return (dataSource) -> { if (dataSource instanceof HikariDataSource) { return new HikariDataSourcePoolMetadata( (HikariDataSource) dataSource); } return null; }; } } // dbcp2連接池的配置,很不幸,BasicDataSource不在默認包中,所以這個連接池不會生效 @Configuration @ConditionalOnClass(BasicDataSource.class) static class CommonsDbcp2PoolDataSourceMetadataProviderConfiguration { @Bean public DataSourcePoolMetadataProvider commonsDbcp2PoolDataSourceMetadataProvider() { return (dataSource) -> { if (dataSource instanceof BasicDataSource) { return new CommonsDbcp2DataSourcePoolMetadata( (BasicDataSource) dataSource); } return null; }; } } }
從上面的代碼可以知道spring-boot默認實現(xiàn)了hikari連接池。
備注5: @Import引入了DataSourceConfiguration的幾個內部類(Hikari、Tomcat、Dbcp2、Generic) ,上面我們也說了Hikari是親兒子,所以Tomcat和Dbcp2肯定是死在了@ConditionalOnClass上了,所以我們只看Hikari和Generic
abstract class DataSourceConfiguration { //HikariDataSource肯定存在,往下走 @ConditionalOnClass(HikariDataSource.class) // 在此之前還沒有實例化DataSource,往下走(如果我們在應用中主動實現(xiàn)了datasource,那默認的hikari就不會實現(xiàn), //這個也很常見,比如我們使用阿里巴巴的durid連接池,也是基于類似的原理,當然比這要稍微復雜些) @ConditionalOnMissingBean(DataSource.class) // 當配置 spring.datasource.type=com.zaxxer.hikari.HikariDataSource或該配置不存在時,往下走 @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true) static class Hikari { // 若以上4個注解的條件都滿足,則在這里實例化一個HikariDataSource的bean,很顯然它也是DataSource的子類 @Bean @ConfigurationProperties(prefix = "spring.datasource.hikari") public HikariDataSource dataSource(DataSourceProperties properties) { HikariDataSource dataSource = createDataSource(properties, HikariDataSource.class); if (StringUtils.hasText(properties.getName())) { dataSource.setPoolName(properties.getName()); } return dataSource; } } // 若DataSource沒有bean存在,則往下走,很不幸,在上面已經實例化過HikariDataSource,止步于此, // 看去來這只是為了避免之前都沒有實例化dataSource,這里來默認一個dataSource @ConditionalOnMissingBean(DataSource.class) @ConditionalOnProperty(name = "spring.datasource.type") static class Generic { @Bean public DataSource dataSource(DataSourceProperties properties) { return properties.initializeDataSourceBuilder().build(); } }
至此,數(shù)據源和連接池都已實例化完成。講解的非常粗糙,但是這不重要,因為我們今天的主角可不是dataSource,別忘了我們要講的是spring-boot-autoconfigure,通過上面的例子,其實最關鍵的是幾個注解
@ConditionalOnClass : 當對應的類存在時則表示滿足條件,一個典型的例子,spring-boot中經常會在你添加了某一個模塊的maven依賴之后,該功能就自動開啟了,比如添加org.flywaydb.flyway-core的依賴包后會默認開啟flyway。
@Import : 類似于spring-mvc的import標簽
@ConditionalOnMissingBean: 當對應的bean在beanFactory不存在時表示滿足條件,一般用于只允許類的一個bean存在
@ConditionalOnBean: 與ConditionalOnMissingBean的作用相反,一般用于依賴的bean存在時才會實例化
@ConditionalOnProperty: 當對應的屬性值為指定值時表示滿足條件
因此我們在接觸到一個新的模塊后,如果spring-boot會自動配置它,那么我們可以在spring-boot-autoconfigure模塊下找到對應的包,然后找到以AutoConfiguration結尾的類,比如flyway的FlywayAutoConfiguration,cassandra的CassandraAutoConfiguration等等,然后再配合上面的幾個注解,就能很快了解新模塊的加載過程。
有些愛思考的同學就要問了,你怎么知道要去找以AutoConfiguration結尾的類,這個就引入了另一個話題,spring-boot是如何實現(xiàn)自動配置的,它怎么知道需要加載哪些AutoConfiguration,這個其實是用到了spring-factories機制,關于spring-factories的詳細原理需要單獨寫一篇文章來介紹,這里只是簡單說一下它在autoconfigure中的應用,我們直接來看一下spring-boot-autoconfigure-2.0.6.RELEASE.jar包下的spring.factories文件
里面有這樣的一部分配置(如下),key是org.springframework.boot.autoconfigure.EnableAutoConfiguration,value是各個以逗號隔開的*AutoConfiguration,結合spring-factories的運行原理,我們就可以知道所有的自動配置是從這里開始加載的。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\ org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\ org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\ org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\ org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\ org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\ org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\ org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\ org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\ org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\ org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\ org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\ org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\ org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\ org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\ org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\ org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\ org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\ org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\ org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\ org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\ org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\ org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\ org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\ org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\ org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\ org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\ org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\ org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\ org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\ org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\ org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\ org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\ org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\ org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\ org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\ org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\ org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\ org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\ org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\ org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\ org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\ org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\ org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\ org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\ org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\ org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\ org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\ org.springframework.boot.autoconfigure.security.servlet.SecurityRequestMatcherProviderAutoConfiguration,\ org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\ org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\ org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\ org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\ org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\ org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\ org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration,\ org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\ org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\ org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\ org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\ org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\ org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\ org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\ org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\ org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\ org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\ org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\ org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\ org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\ org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\ org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\ org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\ org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\ org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\ org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\ org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration
知道了原理后,我們也可以自己定義自己的自動配置模塊,只需要在自己的jar包下添加 MATA-INF/spring.factories文件,然后加上配置org.springframework.boot.autoconfigure.EnableAutoConfiguration=[我們自己寫的autoconfigure],舉個常用的例子,上面我們提到了阿里巴巴的durid數(shù)據庫連接池,durid也專門提供了自動配置支持
其中spring.factories中的內容是這樣的
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
DruidDataSourceAutoConfigure.java中的內容如下,跟我們之前介紹的dataSource的例子差不多,都是使用了幾個常用的注解來實現(xiàn)自動配置。
總結一下,spring-boot通過spring-boot-autoconfigure體現(xiàn)了"約定優(yōu)于配置"這一設計原則,而spring-boot-autoconfigure主要用到了spring.factories和幾個常用的注解條件來實現(xiàn)自動配置,思路很清晰也很簡單。
但是我特別偏愛spring-boot-autoconfigure這個模塊,其中一個最大的好處就是,當我在使用一個新的功能或模塊時,比如spring內置的flyway,cassandra或是阿里巴巴第三方的durid,我只需要順著spring-boot-autoconfigure的自動配置,就能大致了解新模塊的加載過程以及運行的原理,這對于我們熟悉新的模塊確實起到了事半功倍的效果,希望spring-boot-autoconfigure也能給各位帶來更好的學習體驗。
到此這篇關于spring-boot-autoconfigure的文章就介紹到這了,更多相關spring-boot-autoconfigure內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
String實例化及static final修飾符實現(xiàn)方法解析
這篇文章主要介紹了String實例化及static final修飾符實現(xiàn)方法解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-09-09Java編程實現(xiàn)基于圖的深度優(yōu)先搜索和廣度優(yōu)先搜索完整代碼
這篇文章主要介紹了Java編程實現(xiàn)基于圖的深度優(yōu)先搜索和廣度優(yōu)先搜索完整代碼,具有一定借鑒價值,需要的朋友可以了解下。2017-12-12SpringBoot Pom文件依賴及Starter啟動器詳細介紹
這篇文章主要介紹了SpringBoot Pom文件的依賴與starter啟動器的作用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-09-09使用Java創(chuàng)建數(shù)據透視表并導出為PDF的方法
數(shù)據透視分析是一種強大的工具,可以幫助我們從大量數(shù)據中提取有用信息并進行深入分析,本文將介紹如何使用Java來構建PivotTable以及實現(xiàn)數(shù)據透視分析,并將其導出為PDF2023-10-10