在學(xué)習(xí)Spring Boot的過程中,接觸最多的就是starter??梢哉J(rèn)為starter是一種服務(wù)——使得使用某個(gè)功能的開發(fā)者不需要關(guān)注各種依賴庫的處理,不需要具體的配置信息,由Spring Boot自動(dòng)通過classpath路徑下的類發(fā)現(xiàn)需要的Bean,并織入bean。舉個(gè)例子,spring-boot-starter-jdbc這個(gè)starter的存在,使得我們只需要在BookPubApplication下用@Autowired
引入DataSource的bean就可以,Spring Boot會(huì)自動(dòng)創(chuàng)建DataSource的實(shí)例。
這里我們會(huì)用一個(gè)不太規(guī)范的starter展示Spring Boot的自動(dòng)配置的運(yùn)行原理。Spring Boot的自動(dòng)配置、Command-line Runner一文中曾利用StartupRunner類在程序運(yùn)行啟動(dòng)后首先查詢數(shù)據(jù)庫中書的數(shù)目,現(xiàn)在換個(gè)需求:在系統(tǒng)啟動(dòng)后打印各個(gè)實(shí)體的數(shù)量。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<!-- version繼承父模塊的-->
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>1.9.3.RELEASE</version>
</dependency></dependencies>
package com.test.bookpubstarter.dbcount;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.data.repository.CrudRepository;
import java.util.Collection;
public class DbCountRunner implements CommandLineRunner {
protected final Logger logger = LoggerFactory.getLogger(DbCountRunner.class);
private Collection<CrudRepository> repositories;
public DbCountRunner(Collection<CrudRepository> repositories) {
this.repositories = repositories;
}
@Override
public void run(String... strings) throws Exception {
repositories.forEach(crudRepository -> {
logger.info(String.format("%s has %s entries",
getRepositoryName(crudRepository.getClass()),
crudRepository.count()));
});
}
private static String getRepositoryName(Class crudRepositoryClass) {
for (Class repositoryInterface : crudRepositoryClass.getInterfaces()) {
if (repositoryInterface.getName().startsWith("com.test.bookpub.repository")) {
return repositoryInterface.getSimpleName();
}
}
return "UnknownRepository";
}
}
package com.test.bookpubstarter.dbcount;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.repository.CrudRepository;
import java.util.Collection;
@Configuration
public class DbCountAutoConfiguration {
@Bean
public DbCountRunner dbCountRunner(Collection<CrudRepository> repositories) {
return new DbCountRunner(repositories);
}
}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.test.bookpubstarter.dbcount.DbCountAutoConfiguration
<dependency>
<groupId>com.test</groupId>
<artifactId>db-count-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
http://wiki.jikexueyuan.com/project/spring-boot-cookbook-zh/images/c0.png" alt="自己的starter簡單演示.png" />
正規(guī)的starter是一個(gè)獨(dú)立的工程,然后在maven中新倉庫注冊發(fā)布,其他開發(fā)人員就可以使用你的starter了。
常見的starter會(huì)包括下面幾個(gè)方面的內(nèi)容:
在應(yīng)用程序啟動(dòng)過程中,Spring Boot使用SpringFactoriesLoader類加載器查找org.springframework.boot.autoconfigure.EnableAutoConfiguration關(guān)鍵字對應(yīng)的Java配置文件。Spring Boot會(huì)遍歷在各個(gè)jar包種META-INF目錄下的spring.factories文件,構(gòu)建成一個(gè)配置文件鏈表。除了EnableAutoConfiguration關(guān)鍵字對應(yīng)的配置文件,還有其他類型的配置文件:
Spring Boot的starter在編譯時(shí)不需要依賴Spring Boot的庫。這個(gè)例子中依賴spring boot并不是因?yàn)樽詣?dòng)配置要用spring boot,而僅僅是因?yàn)樾枰獙?shí)現(xiàn)CommandLineRunner接口。
@ConditionalOnMissingBean的作用是:只有對應(yīng)的ban在系統(tǒng)中都沒有被創(chuàng)建,它修飾的初始化代碼塊才會(huì)執(zhí)行,用戶自己手動(dòng)創(chuàng)建的bean優(yōu)先;