spring-boot-autoconfigure模塊用法詳解
初次接觸spring-boot的時(shí)候,我們經(jīng)常會(huì)看到這樣的文章:“為什么要使用spring-boot” "spring-boot與spring mvc有什么區(qū)別",在這些文章中幾乎都會(huì)出現(xiàn)這樣的一句話(huà)“約定優(yōu)于配置”,確實(shí)是這樣的,spring-boot與spring-mvc的一個(gè)重要區(qū)別就是spring-boot遵循“約定優(yōu)于配置”這一原則,而spring-boot-autoconfigure模塊正是完美的實(shí)現(xiàn)這個(gè)原則,所以我們今天就來(lái)說(shuō)一說(shuō)spring-boot-autoconfigure這個(gè)模塊。
顧名思義,autoconfigure就是自動(dòng)配置的意思,我們先看一個(gè)比較常用的例子,我們都知道,對(duì)于90%的web項(xiàng)目我們都需要使用數(shù)據(jù)庫(kù)(比如mysql),所以就需要用到datasource,我們就先以datasource的自動(dòng)配置為例吧。
使用過(guò)spring-boot的都知道,我們只需要在application.yml中進(jìn)行以下配置即可在應(yīng)用中使用對(duì)應(yīng)的數(shù)據(jù)庫(kù)連接
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
對(duì)于習(xí)慣了spring-mvc的同學(xué)來(lái)說(shuō),這真是太簡(jiǎn)潔了!我們下面來(lái)看一下spring-boot-autoconfigure是怎樣簡(jiǎn)化這些步驟的,話(huà)不多說(shuō),直奔關(guān)鍵代碼: 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 { // 這里是為了開(kāi)啟一個(gè)內(nèi)嵌的datasource,因?yàn)椴粷M(mǎn)足某些條件,因此最終不會(huì)實(shí)例化一個(gè)dataSource @Configuration @Conditional(EmbeddedDatabaseCondition.class) @ConditionalOnMissingBean({ DataSource.class, XADataSource.class }) @Import(EmbeddedDataSourceConfiguration.class) protected static class EmbeddedDatabaseConfiguration { } @Configuration @Conditional(PooledDataSourceCondition.class) // 由于上面的EmbeddedDatabase沒(méi)有實(shí)例化成功,所以在這里還沒(méi)有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 這個(gè)注解我就不解釋了,用過(guò)spring-boot的都知道是干啥的
備注2: @ConditionalOnClass表示只有classpath中能找到DataSource.class和EmbeddedDatabaseType.class時(shí),DataSourceAutoConfiguration這個(gè)類(lèi)才會(huì)被spring容器實(shí)例化,這其實(shí)也解釋了為什么我們有時(shí)候只需要在pom.xml添加某些依賴(lài)包,某些功能就自動(dòng)打開(kāi)了,就是這個(gè)注解干的好事兒。
備注3: @EnableConfigurationProperties引入了DataSourceProperties的配置,簡(jiǎn)單看一下代碼,是不是有一種似曾相識(shí)的感覺(jué), 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,這里我們重點(diǎn)關(guān)注一下DataSourceInitializationConfiguration
@Configuration public class DataSourcePoolMetadataProvidersConfiguration { // tomcat自帶的datasource連接池,由于默認(rèn)情況下spring-boot未引入org.apache.tomcat.jdbc.pool.DataSource對(duì)應(yīng)的依賴(lài)包, // 根據(jù)@ConditionalOnClass注解的作用,這個(gè)配置不會(huì)生效 @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默認(rèn)的連接池(據(jù)說(shuō)速度超快),HikariDataSource的包默認(rèn)在spring-boot的全家桶中, //所以最終會(huì)實(shí)例化DataSourcePoolMetadataProvider 的一個(gè)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不在默認(rèn)包中,所以這個(gè)連接池不會(huì)生效 @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默認(rèn)實(shí)現(xiàn)了hikari連接池。
備注5: @Import引入了DataSourceConfiguration的幾個(gè)內(nèi)部類(lèi)(Hikari、Tomcat、Dbcp2、Generic) ,上面我們也說(shuō)了Hikari是親兒子,所以Tomcat和Dbcp2肯定是死在了@ConditionalOnClass上了,所以我們只看Hikari和Generic
abstract class DataSourceConfiguration { //HikariDataSource肯定存在,往下走 @ConditionalOnClass(HikariDataSource.class) // 在此之前還沒(méi)有實(shí)例化DataSource,往下走(如果我們?cè)趹?yīng)用中主動(dòng)實(shí)現(xiàn)了datasource,那默認(rèn)的hikari就不會(huì)實(shí)現(xiàn), //這個(gè)也很常見(jiàn),比如我們使用阿里巴巴的durid連接池,也是基于類(lèi)似的原理,當(dāng)然比這要稍微復(fù)雜些) @ConditionalOnMissingBean(DataSource.class) // 當(dāng)配置 spring.datasource.type=com.zaxxer.hikari.HikariDataSource或該配置不存在時(shí),往下走 @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true) static class Hikari { // 若以上4個(gè)注解的條件都滿(mǎn)足,則在這里實(shí)例化一個(gè)HikariDataSource的bean,很顯然它也是DataSource的子類(lèi) @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沒(méi)有bean存在,則往下走,很不幸,在上面已經(jīng)實(shí)例化過(guò)HikariDataSource,止步于此, // 看去來(lái)這只是為了避免之前都沒(méi)有實(shí)例化dataSource,這里來(lái)默認(rèn)一個(gè)dataSource @ConditionalOnMissingBean(DataSource.class) @ConditionalOnProperty(name = "spring.datasource.type") static class Generic { @Bean public DataSource dataSource(DataSourceProperties properties) { return properties.initializeDataSourceBuilder().build(); } }
至此,數(shù)據(jù)源和連接池都已實(shí)例化完成。講解的非常粗糙,但是這不重要,因?yàn)槲覀兘裉斓闹鹘强刹皇莇ataSource,別忘了我們要講的是spring-boot-autoconfigure,通過(guò)上面的例子,其實(shí)最關(guān)鍵的是幾個(gè)注解
@ConditionalOnClass : 當(dāng)對(duì)應(yīng)的類(lèi)存在時(shí)則表示滿(mǎn)足條件,一個(gè)典型的例子,spring-boot中經(jīng)常會(huì)在你添加了某一個(gè)模塊的maven依賴(lài)之后,該功能就自動(dòng)開(kāi)啟了,比如添加org.flywaydb.flyway-core的依賴(lài)包后會(huì)默認(rèn)開(kāi)啟flyway。
@Import : 類(lèi)似于spring-mvc的import標(biāo)簽
@ConditionalOnMissingBean: 當(dāng)對(duì)應(yīng)的bean在beanFactory不存在時(shí)表示滿(mǎn)足條件,一般用于只允許類(lèi)的一個(gè)bean存在
@ConditionalOnBean: 與ConditionalOnMissingBean的作用相反,一般用于依賴(lài)的bean存在時(shí)才會(huì)實(shí)例化
@ConditionalOnProperty: 當(dāng)對(duì)應(yīng)的屬性值為指定值時(shí)表示滿(mǎn)足條件
因此我們?cè)诮佑|到一個(gè)新的模塊后,如果spring-boot會(huì)自動(dòng)配置它,那么我們可以在spring-boot-autoconfigure模塊下找到對(duì)應(yīng)的包,然后找到以AutoConfiguration結(jié)尾的類(lèi),比如flyway的FlywayAutoConfiguration,cassandra的CassandraAutoConfiguration等等,然后再配合上面的幾個(gè)注解,就能很快了解新模塊的加載過(guò)程。
有些愛(ài)思考的同學(xué)就要問(wèn)了,你怎么知道要去找以AutoConfiguration結(jié)尾的類(lèi),這個(gè)就引入了另一個(gè)話(huà)題,spring-boot是如何實(shí)現(xiàn)自動(dòng)配置的,它怎么知道需要加載哪些AutoConfiguration,這個(gè)其實(shí)是用到了spring-factories機(jī)制,關(guān)于spring-factories的詳細(xì)原理需要單獨(dú)寫(xiě)一篇文章來(lái)介紹,這里只是簡(jiǎn)單說(shuō)一下它在autoconfigure中的應(yīng)用,我們直接來(lái)看一下spring-boot-autoconfigure-2.0.6.RELEASE.jar包下的spring.factories文件
里面有這樣的一部分配置(如下),key是org.springframework.boot.autoconfigure.EnableAutoConfiguration,value是各個(gè)以逗號(hào)隔開(kāi)的*AutoConfiguration,結(jié)合spring-factories的運(yùn)行原理,我們就可以知道所有的自動(dòng)配置是從這里開(kāi)始加載的。
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
知道了原理后,我們也可以自己定義自己的自動(dòng)配置模塊,只需要在自己的jar包下添加 MATA-INF/spring.factories文件,然后加上配置org.springframework.boot.autoconfigure.EnableAutoConfiguration=[我們自己寫(xiě)的autoconfigure],舉個(gè)常用的例子,上面我們提到了阿里巴巴的durid數(shù)據(jù)庫(kù)連接池,durid也專(zhuān)門(mén)提供了自動(dòng)配置支持
其中spring.factories中的內(nèi)容是這樣的
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
DruidDataSourceAutoConfigure.java中的內(nèi)容如下,跟我們之前介紹的dataSource的例子差不多,都是使用了幾個(gè)常用的注解來(lái)實(shí)現(xiàn)自動(dòng)配置。
總結(jié)一下,spring-boot通過(guò)spring-boot-autoconfigure體現(xiàn)了"約定優(yōu)于配置"這一設(shè)計(jì)原則,而spring-boot-autoconfigure主要用到了spring.factories和幾個(gè)常用的注解條件來(lái)實(shí)現(xiàn)自動(dòng)配置,思路很清晰也很簡(jiǎn)單。
但是我特別偏愛(ài)spring-boot-autoconfigure這個(gè)模塊,其中一個(gè)最大的好處就是,當(dāng)我在使用一個(gè)新的功能或模塊時(shí),比如spring內(nèi)置的flyway,cassandra或是阿里巴巴第三方的durid,我只需要順著spring-boot-autoconfigure的自動(dòng)配置,就能大致了解新模塊的加載過(guò)程以及運(yùn)行的原理,這對(duì)于我們熟悉新的模塊確實(shí)起到了事半功倍的效果,希望spring-boot-autoconfigure也能給各位帶來(lái)更好的學(xué)習(xí)體驗(yàn)。
到此這篇關(guān)于spring-boot-autoconfigure的文章就介紹到這了,更多相關(guān)spring-boot-autoconfigure內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
老生常談Java?網(wǎng)絡(luò)編程?——?Socket?詳解
這篇文章主要介紹了Java?網(wǎng)絡(luò)編程?——?Socket?相關(guān)知識(shí),本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-05-05String實(shí)例化及static final修飾符實(shí)現(xiàn)方法解析
這篇文章主要介紹了String實(shí)例化及static final修飾符實(shí)現(xiàn)方法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09Java編程實(shí)現(xiàn)基于圖的深度優(yōu)先搜索和廣度優(yōu)先搜索完整代碼
這篇文章主要介紹了Java編程實(shí)現(xiàn)基于圖的深度優(yōu)先搜索和廣度優(yōu)先搜索完整代碼,具有一定借鑒價(jià)值,需要的朋友可以了解下。2017-12-12SpringBoot Pom文件依賴(lài)及Starter啟動(dòng)器詳細(xì)介紹
這篇文章主要介紹了SpringBoot Pom文件的依賴(lài)與starter啟動(dòng)器的作用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-09-09idea項(xiàng)目文件夾橫向顯示,縱向顯示的解決方法
這篇文章主要介紹了idea項(xiàng)目文件夾橫向顯示,縱向顯示的解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08使用Java創(chuàng)建數(shù)據(jù)透視表并導(dǎo)出為PDF的方法
數(shù)據(jù)透視分析是一種強(qiáng)大的工具,可以幫助我們從大量數(shù)據(jù)中提取有用信息并進(jìn)行深入分析,本文將介紹如何使用Java來(lái)構(gòu)建PivotTable以及實(shí)現(xiàn)數(shù)據(jù)透視分析,并將其導(dǎo)出為PDF2023-10-10