首先,咱們來簡單統計一下SpringBoot核心工程的源碼java文件數量:html
咱們cd到spring-boot-autoconfigure工程根目錄下。執行java
$ tree | grep -c .java$
模塊 | java文件數 |
---|---|
spring-boot | 551 |
spring-boot-actuator | 423 |
spring-boot-autoconfigure | 783 |
spring-boot-devtools | 169 |
spring-boot-cli | 180 |
spring-boot-tools | 355 |
模塊 | 描述 |
---|---|
spring-boot-starter | Spring Boot 核心模塊,提供全部的基礎功能。 其餘模塊都要依賴它,因此沒有必要明確聲明。 |
spring-boot-starter-actuator | 提供了監視,管理應用程序和審覈的功能。 |
spring-boot-starter-jdbc | 提供了鏈接和使用JDBC數據庫,鏈接池等的支持。 |
spring-boot-starter-data-jpa | 爲使用Java Persistence API(如Hibernate等)提供了必要的類庫。 |
spring-boot-starter-data-* | 帶有「data-*」的集合組件爲諸如MongoDB,Data-Rest或Solr之類的數據存儲提供支持。 |
spring-boot-starter-security | 爲Spring-security提供全部必需的依賴。 |
spring-boot-starter-social-* | 提供了與Facebook, Twitter, 和 LinkedIn 整合的功能。 |
spring-boot-starter-test | 包含Spring-test和各類測試框架(如JUnit和Mockito等)的依賴。 |
spring-boot-starter-web | 提供了Web應用程序開發所需的全部依賴。做爲spring-boot-starter-hateoas, spring-boot-starter-websocket, spring-boot-starter-mobile, 和 spring-boot-starter-ws 的補充。以及各類模板渲染模塊sping-boot-starter-thymeleaf和spring-boot-starter-mustache。 |
咱們能夠看到有783個java文件。spring-boot核心工程有551個java文件。從上面的java文件數量大體能夠看出,SpringBoot技術框架的核心組成部分:react
spring-boot-autoconfigure spring-boot spring-boot-tools
咱們把SpringBoot源碼導入IntelliJ IDEA,查看artifact的所有依賴關係。linux
IDEA有個Maven Projects窗口,通常在右側可以找到,若是沒有能夠從菜單欄打開:View>Tool Windows>Maven Projects;git
選擇要分析的maven module(idea的module至關於eclipse的project),右擊show dependencies,會出來該module的所有依賴關係圖,很是清晰細緻。github
例如,spring-boot-starter-freemarker的依賴圖分析以下:web
在spring-boot-build 的pom中,咱們能夠看到:redis
<modules> <module>spring-boot-dependencies</module> <module>spring-boot-parent</module> <module>spring-boot-tools</module> <module>spring-boot</module> <module>spring-boot-test</module> <module>spring-boot-autoconfigure</module> <module>spring-boot-test-autoconfigure</module> <module>spring-boot-actuator</module> <module>spring-boot-devtools</module> <module>spring-boot-docs</module> <module>spring-boot-starters</module> <module>spring-boot-actuator-docs</module> <module>spring-boot-cli</module> </modules>
其中,在spring-boot-dependencies中,SpringBoot項目維護了一份龐大依賴。這些依賴的版本都是通過實踐,測試經過,不會發生依賴衝突的。就這樣一個事情,就大大減小了Spring開發過程當中,出現jar包衝突的機率。spring-boot-parent依賴spring-boot-dependencies。spring
下面咱們簡要介紹一下SpringBoot子modules。sql
spring-boot
SpringBoot核心工程。
spring-boot-starters
是SpringBoot的啓動服務工程。
spring-boot-autoconfigure
是SpringBoot實現自動配置的核心工程。
spring-boot-actuator
提供SpringBoot應用的外圍支撐性功能。 好比:
spring-boot-tools
提供了SpringBoot開發者的經常使用工具集。諸如,spring-boot-gradle-plugin,spring-boot-maven-plugin就是這個工程裏面的。
spring-boot-cli
是Spring Boot命令行交互工具,可用於使用Spring進行快速原型搭建。你能夠用它直接運行Groovy腳本。若是你不喜歡Maven或Gradle,Spring提供了CLI(Command Line Interface)來開發運行Spring應用程序。你可使用它來運行Groovy腳本,甚至編寫自定義命令。
Spring boot中的starter概念是很是重要的機制,可以拋棄之前繁雜的配置,統一集成進starter,應用者只須要引入starter jar包,spring boot就能自動掃描到要加載的信息。
starter讓咱們擺脫了各類依賴庫的處理,須要配置各類信息的困擾。Spring Boot會自動經過classpath路徑下的類發現須要的Bean,並織入bean。
例如,若是你想使用Spring和用JPA訪問數據庫,你只要依賴 spring-boot-starter-data-jpa 便可。
目前,github上spring-boot項目的最新的starter列表spring-boot/spring-boot-starters以下:
spring-boot-starter spring-boot-starter-activemq spring-boot-starter-actuator spring-boot-starter-amqp spring-boot-starter-aop spring-boot-starter-artemis spring-boot-starter-batch spring-boot-starter-cache spring-boot-starter-cloud-connectors spring-boot-starter-data-cassandra spring-boot-starter-data-couchbase spring-boot-starter-data-elasticsearch spring-boot-starter-data-jpa spring-boot-starter-data-ldap spring-boot-starter-data-mongodb spring-boot-starter-data-mongodb-reactive spring-boot-starter-data-neo4j spring-boot-starter-data-redis spring-boot-starter-data-rest spring-boot-starter-data-solr spring-boot-starter-freemarker spring-boot-starter-groovy-templates spring-boot-starter-hateoas spring-boot-starter-integration spring-boot-starter-jdbc spring-boot-starter-jersey spring-boot-starter-jetty spring-boot-starter-jooq spring-boot-starter-jta-atomikos spring-boot-starter-jta-bitronix spring-boot-starter-jta-narayana spring-boot-starter-log4j2 spring-boot-starter-logging spring-boot-starter-mail spring-boot-starter-mobile spring-boot-starter-mustache spring-boot-starter-parent spring-boot-starter-reactor-netty spring-boot-starter-security spring-boot-starter-social-facebook spring-boot-starter-social-linkedin spring-boot-starter-social-twitter spring-boot-starter-test spring-boot-starter-thymeleaf spring-boot-starter-tomcat spring-boot-starter-undertow spring-boot-starter-validation spring-boot-starter-web spring-boot-starter-web-services spring-boot-starter-webflux spring-boot-starter-websocket
(源代碼目錄執行shell:l|awk '{print $9}', l|awk '{print $9}'|grep -c 'starter')
共52個。每一個starter工程裏面的pom描述有相應的介紹。具體的說明,參考官網文檔[1]。關於這些starters的使用例子,能夠參考spring-boot/spring-boot-samples
好比說,spring-boot-starter是:
Core starter, including auto-configuration support, logging and YAML
這是Spring Boot的核心啓動器,包含了自動配置、日誌和YAML。它的項目依賴圖以下:
能夠看出,這些starter只是配置,真正作自動化配置的代碼的是在spring-boot-autoconfigure裏面。同時spring-boot-autoconfigure依賴spring-boot工程,這個spring-boot工程是SpringBoot的核心。
SpringBoot會基於你的classpath中的jar包,試圖猜想和配置您可能須要的bean。
例如,若是你的classpath中有tomcat-embedded.jar,你可能會想要一個TomcatEmbeddedServletContainerFactory Bean (SpringBoot經過獲取EmbeddedServletContainerFactory來啓動對應的web服務器。經常使用的兩個實現類是TomcatEmbeddedServletContainerFactory和JettyEmbeddedServletContainerFactory)。
其餘的全部基於Spring Boot的starter都依賴這個spring-boot-starter。好比說spring-boot-starter-actuator的依賴樹,以下圖:
經過@EnableAutoConfiguration啓用Spring應用程序上下文的自動配置,這個註解會導入一個EnableAutoConfigurationImportSelector的類,而這個類會去讀取一個spring.factories下key爲EnableAutoConfiguration對應的全限定名的值。
這個spring.factories裏面配置的那些類,主要做用是告訴Spring Boot這個stareter所須要加載的那些xxxAutoConfiguration類,也就是你真正的要自動註冊的那些bean或功能。而後,咱們實現一個spring.factories指定的類,標上@Configuration註解,一個starter就定義完了。
若是想從本身的starter種讀取應用的starter工程的配置,只須要在入口類上加上以下註解便可:
@EnableConfigurationProperties(MyProperties.class)
是經過org.springframework.core.io.support.SpringFactoriesLoader實現。
SpringFactoriesLoader的實現相似於SPI(Service Provider Interface,在java.util.ServiceLoader的文檔裏有比較詳細的介紹。java SPI提供一種服務發現機制,爲某個接口尋找服務實現的機制。有點相似IOC的思想,就是將裝配的控制權移到程序以外,在模塊化設計中這個機制尤爲重要[3])。
SpringFactoriesLoader會加載classpath下全部JAR文件裏面的META-INF/spring.factories文件。
其中加載spring.factories文件的代碼在loadFactoryNames方法裏:
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; .... public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); try { Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); List<String> result = new ArrayList<>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url)); String factoryClassNames = properties.getProperty(factoryClassName); result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames))); } return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } }
經過org.springframework.boot.autoconfigure.AutoConfigurationImportSelector裏面的getCandidateConfigurations方法,獲取到候選類的名字List<String>。該方法代碼以下:
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; }
其中,getSpringFactoriesLoaderFactoryClass()方法直接返回的是EnableAutoConfiguration.class, 代碼以下:
protected Class<?> getSpringFactoriesLoaderFactoryClass() { return EnableAutoConfiguration.class; }
因此,getCandidateConfigurations方法裏面的這段代碼:
List<String> configurations = SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
會過濾出key爲org.springframework.boot.autoconfigure.EnableAutoConfiguration的全限定名對應的值。全限定名都使用以下命名方法:
包名.外部類名 包名.外部類名$內部類名 e.g: org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
SpringBoot中的META-INF/spring.factories(完整路徑:spring-boot/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories)中關於EnableAutoConfiguration的這段配置以下:
# Auto Configure 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.CassandraRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\ 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.MongoRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.ReactiveMongoDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.ReactiveMongoRepositoriesAutoConfiguration,\ 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.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.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.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.mobile.DeviceResolverAutoConfiguration,\ org.springframework.boot.autoconfigure.mobile.DeviceDelegatingViewResolverAutoConfiguration,\ org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,\ org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\ org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\ org.springframework.boot.autoconfigure.mongo.ReactiveMongoAutoConfiguration,\ org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\ org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\ org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\ org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\ org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,\ org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\ org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration,\ org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\ org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\ org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,\ org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,\ org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,\ org.springframework.boot.autoconfigure.social.TwitterAutoConfiguration,\ 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.reactive.HttpHandlerAutoConfiguration,\ org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerAutoConfiguration,\ org.springframework.boot.autoconfigure.web.reactive.WebFluxAnnotationAutoConfiguration,\ 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.WebSocketAutoConfiguration,\ org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration,\ org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration
固然了,這些AutoConfiguration不是全部都會加載的,會根據AutoConfiguration上的@ConditionalOnClass等條件,再進一步判斷是否加載。咱們下文經過FreeMarkerAutoConfiguration實例來分析整個自動配置的過程。
咱們首先看spring-boot-starter-freemarker工程,目錄結構以下:
. ├── pom.xml ├── spring-boot-starter-freemarker.iml └── src └── main └── resources └── META-INF └── spring.provides 4 directories, 3 files
咱們能夠看出,這個工程沒有任何Java代碼,只有兩個文件:pom.xml跟spring.provides。starter自己在你的應用程序中其實是空的。
其中,
spring.provides文件
provides: freemarker,spring-context-support
主要是給這個starter起個好區分的名字。
Spring Boot 經過starter對項目的依賴進行統一管理. starter利用了maven的傳遞依賴解析機制,把經常使用庫聚合在一塊兒, 組成了針對特定功能而定製的依賴starter。
咱們可使用IDEA提供的maven依賴圖分析的功能(以下圖),獲得spring-boot-starter-freemarker依賴的module。
IDEA提供的maven依賴圖分析
spring-boot-starter-freemarker依賴的module
從上面的依賴圖,咱們能夠清晰看出其間依賴關係。
當Spring Boot Application中自動配置EnableAutoConfiguration的相關類執行完畢以後,Spring Boot會進一步解析對應類的配置信息。若是咱們配置了spring-boot-starter-freemarker ,maven就會經過這個starter所依賴的spring-boot-autoconfigure,自動傳遞到spring-boot-autoconfigure工程中。
咱們來簡單分析一下spring-boot-autoconfigure工程的架構。
其中,FreeMarker的自動配置類是org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration。
下面咱們來簡要分析一下FreeMarkerAutoConfiguration這個類。
在FreeMarkerAutoConfiguration類上面有四行註解:
@Configuration @ConditionalOnClass({ freemarker.template.Configuration.class, FreeMarkerConfigurationFactory.class }) @AutoConfigureAfter(WebMvcAutoConfiguration.class) @EnableConfigurationProperties(FreeMarkerProperties.class) public class FreeMarkerAutoConfiguration { ... }
其中,
(1)@Configuration,是org.springframework.context.annotation包裏面的註解。這麼說吧,用@Configuration註解該類,等價 與XML中配置beans;用@Bean標註方法等價於XML中配置bean。
(2)@ConditionalOnClass,org.springframework.boot.autoconfigure.condition包裏面的註解。意思是當類路徑下有指定的類的條件下,纔會去註冊被標註的類爲一個bean。在上面的代碼中的意思就是,當類路徑中有freemarker.template.Configuration.class,FreeMarkerConfigurationFactory.class兩個類的時候,纔會實例化FreeMarkerAutoConfiguration這個Bean。
(3)@AutoConfigureAfter,org.springframework.boot.autoconfigure包裏面的註解。這個經過註解的名字意思就能夠知道,當WebMvcAutoConfiguration.class這個類實例化完畢,才能實例化FreeMarkerAutoConfiguration(有個前後順序)。SpringBoot使用@ AutoConfigureBefore、@AutoConfigureAfter註解來定義這些配置類的載入順序。
(4)@EnableConfigurationProperties,表示啓動對FreeMarkerProperties.class的內嵌配置支持,自動將FreeMarkerProperties註冊爲一個bean。這個FreeMarkerProperties類裏面就是關於FreeMarker屬性的配置:
@ConfigurationProperties(prefix = "spring.freemarker") public class FreeMarkerProperties extends AbstractTemplateViewResolverProperties { public static final String DEFAULT_TEMPLATE_LOADER_PATH = "classpath:/templates/"; public static final String DEFAULT_PREFIX = ""; public static final String DEFAULT_SUFFIX = ".ftl"; /** * Well-known FreeMarker keys which will be passed to FreeMarker's Configuration. */ private Map<String, String> settings = new HashMap<>(); /** * Comma-separated list of template paths. */ private String[] templateLoaderPath = new String[] { DEFAULT_TEMPLATE_LOADER_PATH }; /** * Prefer file system access for template loading. File system access enables hot * detection of template changes. */ private boolean preferFileSystemAccess = true; public FreeMarkerProperties() { super(DEFAULT_PREFIX, DEFAULT_SUFFIX); } public Map<String, String> getSettings() { return this.settings; } public void setSettings(Map<String, String> settings) { this.settings = settings; } public String[] getTemplateLoaderPath() { return this.templateLoaderPath; } public boolean isPreferFileSystemAccess() { return this.preferFileSystemAccess; } public void setPreferFileSystemAccess(boolean preferFileSystemAccess) { this.preferFileSystemAccess = preferFileSystemAccess; } public void setTemplateLoaderPath(String... templateLoaderPaths) { this.templateLoaderPath = templateLoaderPaths; } }
綜上,當(1)(2)兩個條件知足時,纔會繼續(3)(4)的動做,同時註冊FreeMarkerAutoConfiguration這個Bean。該類的結構以下圖:
咱們來看其內部類FreeMarkerWebConfiguration的代碼:
@Configuration @ConditionalOnClass(Servlet.class) @ConditionalOnWebApplication(type = Type.SERVLET) public static class FreeMarkerWebConfiguration extends FreeMarkerConfiguration { @Bean @ConditionalOnMissingBean(FreeMarkerConfig.class) public FreeMarkerConfigurer freeMarkerConfigurer() { FreeMarkerConfigurer configurer = new FreeMarkerConfigurer(); applyProperties(configurer); return configurer; } @Bean public freemarker.template.Configuration freeMarkerConfiguration( FreeMarkerConfig configurer) { return configurer.getConfiguration(); } @Bean @ConditionalOnMissingBean(name = "freeMarkerViewResolver") @ConditionalOnProperty(name = "spring.freemarker.enabled", matchIfMissing = true) public FreeMarkerViewResolver freeMarkerViewResolver() { FreeMarkerViewResolver resolver = new FreeMarkerViewResolver(); this.properties.applyToViewResolver(resolver); return resolver; } @Bean @ConditionalOnMissingBean @ConditionalOnEnabledResourceChain public ResourceUrlEncodingFilter resourceUrlEncodingFilter() { return new ResourceUrlEncodingFilter(); } }
其中,
(1)@ConditionalOnWebApplication(type = Type.SERVLET), 是當該應用是基於Servlet的Web應用時。
(2)@ConditionalOnMissingBean(name = "freeMarkerViewResolver"),是當Spring容器中不存在freeMarkerViewResolver的Bean時。
(3)@ConditionalOnProperty(name = "spring.freemarker.enabled", matchIfMissing = true),指定的spring.freemarker.enabled屬性是否有。若是沒有(IfMissing),設爲true。
當(1)(2)(3)三個條件都知足,則註冊freeMarkerViewResolver這個Bean。
咱們也能夠自定義咱們本身的my-starter,以及實現對應的@MyEnableAutoConfiguration。SpringBoot有不少第三方starter,其自動配置的原理基本都是這樣,好比mybatis-spring-boot-starter的MybatisAutoConfiguration,閱讀源碼https://github.com/mybatis/spring-boot-starter[4]。
上面文字描述了這麼多,再用一張形象生動的圖來講明[5]:
SpringBoot Autoconfigure 工做原理圖
上面說了這麼多,講的都是讀取properties文件中key爲org.springframework.boot.autoconfigure.EnableAutoConfiguration的全限定名對應的值。SpringBoot內部還有許多其餘的key用於過濾獲得須要加載的類。
# Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\ org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer # Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.autoconfigure.BackgroundPreinitializer # Auto Configuration Import Listeners org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\ org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener # Auto Configuration Import Filters org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\ org.springframework.boot.autoconfigure.condition.OnClassCondition # Failure analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\ org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\ org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer # Template availability providers org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\ org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\ org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\ org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\ org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\ org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider
這些key仍然是定義在spring-boot/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories文件中。
還有對應的用於測試的自動配置,在
spring-boot/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories文件中定義。
另外,咱們使用spring.factories裏還能夠定製應用程序的初始化行爲。這樣咱們就能夠在應用程序載入前操縱Spring的應用程序上下文ApplicationContext。
例如,可使用ConfigurableApplicationContext類的addApplicationListener()方法,在應用上下文ApplicationContext中建立監聽器。
自動配置運行日誌報告功能就是這麼實現的。咱們來看在spring.factories中,Initializers一段的配置:
# Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\ org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer
其中,AutoConfigurationReportLoggingInitializer監聽到系統事件時,好比上下文刷新ContextRefreshedEvent或應用程序啓動故障ApplicationFailedEvent之類的事件,Spring Boot能夠作一些事情。這裏說的代碼在AutoConfigurationReportLoggingInitializer.AutoConfigurationReportListener裏面。關於支持的事件類型supportsEventType的以下:
private class AutoConfigurationReportListener implements GenericApplicationListener { ... @Override public boolean supportsEventType(ResolvableType resolvableType) { Class<?> type = resolvableType.getRawClass(); if (type == null) { return false; } return ContextRefreshedEvent.class.isAssignableFrom(type) || ApplicationFailedEvent.class.isAssignableFrom(type); } @Override public boolean supportsSourceType(Class<?> sourceType) { return true; } @Override public void onApplicationEvent(ApplicationEvent event) { AutoConfigurationReportLoggingInitializer.this.onApplicationEvent(event); } }
要以調試模式啓動應用程序,可使用-Ddebug標識,或者在application.properties文件這添加屬性debug= true。這樣,當咱們以調試模式啓動應用程序時,SpringBoot就能夠幫助咱們建立自動配置的運行報告。對於每一個自動配置,經過報告咱們能夠看到它啓動或失敗的緣由。 這個報告內容格式大體以下:
========================= AUTO-CONFIGURATION REPORT ========================= Positive matches: ----------------- DataSourceAutoConfiguration matched: - @ConditionalOnClass found required classes 'javax.sql.DataSource', 'org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition) DataSourceAutoConfiguration#dataSourceInitializer matched: - @ConditionalOnMissingBean (types: org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer; SearchStrategy: all) did not find any beans (OnBeanCondition) DataSourceAutoConfiguration.PooledDataSourceConfiguration matched: - AnyNestedCondition 2 matched 0 did not; NestedCondition on DataSourceAutoConfiguration.PooledDataSourceCondition.PooledDataSourceAvailable PooledDataSource found supported DataSource; NestedCondition on DataSourceAutoConfiguration.PooledDataSourceCondition.ExplicitType @ConditionalOnProperty (spring.datasource.type) matched (DataSourceAutoConfiguration.PooledDataSourceCondition) - @ConditionalOnMissingBean (types: javax.sql.DataSource,javax.sql.XADataSource; SearchStrategy: all) did not find any beans (OnBeanCondition) ... Exclusions: ----------- None Unconditional classes: ---------------------- org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration
除了SpringBoot官方提供的starter外,還有社區貢獻的不少經常使用的第三方starter,列表可參考[2]。
另外,國內不少公司使用RPC框架dubbo,關於SpringBoot集成dubbo,可參考:https://github.com/linux-china/spring-boot-dubbo。
一般須要如下4個工程:
模塊的真正的實現類,如本文的工程爲first
*-spring-boot/*-spring的工程:此工程是*-spring-boot-autoconfigure和*-spring-boot-starter的父工程類。本例子裏是first-spring-boot。此工程的命名規則以下:若是你在這個工程中引入spring依賴,則工程名稱爲*-spring,若是引入spring-boot依賴,則工程名稱爲*-spring-boot。
*-spring-boot-autoconfigure工程:配置自動配置類,本例的名稱first-spring-boot-autoconfigure
*-spring-boot-starter工程:空工程類,在pom.xml中定義須要引入jar,本例的名稱first-spring-boot-starter
測試工程:
test-main:演示如何使用本身的first-spring-boot-starter
例子的功能說明:
定義ITestService接口和此接口的兩個實現類,根據咱們的配置,程序自動初始化指定的一個類。
若是咱們的FirstModuleAutoConfiguration 的初始化必須依賴其餘的自動化配置類(如OtherModuleAutoConfiguration.class),則在此類上增長如下註解
@AutoConfigureAfter(OtherModuleAutoConfiguration.class)
咱們還能夠在配置類定義如下註解
@AutoConfigureAfter: 提示自動配置應在其餘指定的自動配置類以後應用。
@AutoConfigureBefore: 提示自動配置應在其餘指定的自動配置類以前應用
@AutoConfigureOrder:定義配置類執行的順序
另外咱們也能夠加上如下@Conditional條件註解
@ConditionalOnBean:當容器裏有指定的Bean 的條件下。
@ConditionalOnMissingBean:當容器裏沒有指定Bean 的狀況下
@ConditionalOnClass:當類路徑下有指定的類的條件下。
@ConditionalOnMissingClass:當類路徑下沒有指定的類的條件下。
@ConditionalOnExpression:基於SpEL 表達式做爲判斷條件。
@ConditionalOnJava:基於JVM 版本做爲判斷條件。
@ConditionalOnJndi:在JNDI存在的條件下查找指定的位置。
@ConditionalOnProperty:指定的屬性是否有指定的值。
@ConditionalOnResource:類路徑是否有指定的值。
@ConditionalOnSingleCandidate:當指定Bean 在容器中只有一個,或者雖然有多個可是指定首選的Bean。
@ConditionalOnWebApplication:當前項目是Web 項目的條件下。
@ConditionalOnNotWebApplication:當前項目不是Web 項目的條件下。
src/resources/META-INF/spring.factories:
配置FirstModuleAutoConfiguration在此文件,則spring boot會自動生成初始化此類
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.hry.spring.first.autoconfigure.FirstModuleAutoConfiguration
此文件說明此工程依賴的模塊,和pom.xml不一樣的地方這個文件主要給IDE使用,IDE會根據此文件提示使用者此模塊的依賴jar。因此此文件就算什麼都不配,對first模塊使用也沒有什麼影響,最多IDE提示少一些。
英文說明:
It’s for tooling. STS (and other IDEs if they chose to) can index those files and make autocomplete suggestions based on stuff that isn’t yet on the classpath.’
spring.provides內容以下:
provides: spring-boot
參考資料:
1.http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#using-boot-starter
2.https://github.com/spring-projects/spring-boot/tree/master/spring-boot-starters
3.http://www.cnblogs.com/javaee6/p/3714719.html
4.https://github.com/mybatis/spring-boot-starter
5.https://afoo.me/posts/2015-07-09-how-spring-boot-works.html