在你們使用Spring Boot進行開發的過程當中,應該能夠接觸到Spring Boot提供的不少Starter。好比html
spring-boot-starter-web
spring-boot-starter-jdbc
在Spring Boot啓動的過程當中,會去找classpath:META-INF/spring.factories
文件,來決定加載哪些AutoConfiguration類。
讓咱們看一下spring-boot-autoconfigure項目中的spring.factories
文件。下面列出部分AutoConfiguration類。java
# 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.data.redis.RedisAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\ ...
Spring Boot會嘗試去運行全部org.springframework.boot.autoconfigure.EnableAutoConfiguration
列出的AutoConfiguration類。此處你們能夠會有疑問,不少我在項目裏沒有用到。對應組件是否是也會被初始化?答案是不會。咱們用RedisAutoConfiguration
爲例來看一下背後發生了什麼。git
@Configuration @ConditionalOnClass(RedisOperations.class) @EnableConfigurationProperties(RedisProperties.class) @Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class }) public class RedisAutoConfiguration { @Bean @ConditionalOnMissingBean(name = "redisTemplate") public RedisTemplate<Object, Object> redisTemplate( RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { RedisTemplate<Object, Object> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); return template; } @Bean @ConditionalOnMissingBean public StringRedisTemplate stringRedisTemplate( RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { StringRedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; } }
@Configuration
定義Configuration組件@ConditionalOnClass(RedisOperations.class)
在classpath中若是有RedisOperation
類,則會運行此AutoConfiguration。反之則不會運行。@ConditionalOnMissingBean(name = "redisTemplate")
若是在Spring容器中沒有名爲redisTemplate
的Bean被註冊,則執行redisTemplate()方法。反之則不會執行。注:Spring Boot提供了一系列@Condition選擇,同時還能夠實現自定義Condition。參考Spring Boot - Condition Annotationsgithub
AutoConfiguration Hints功能主要便於開發人員在作配置時,IDE能夠提示auto complete。以下截圖:
Auto Complete信息包括:web
具體信息在additional-spring-configuration-metadata.json
中定義redis
public class FooService { private final String fooMessage; private final String barMessage; public FooService(String fooMessage, String barMessage) { this.fooMessage = fooMessage; this.barMessage = barMessage; } public String getFooMessage() { return this.fooMessage; } public String getBarMessage() { return this.barMessage; } }
package io.markfredchen.custom.starter.config; import ...; @Configuration @PropertySource("classpath:config/foo.properties") public class FooAutoConfiguration { @Value("${foo.fooMessage}") private String fooMessage; @Value("${foo.barMessage}") private String barMessage; @Bean @ConditionalOnMissingBean public FooService fooService() { return new FooService(fooMessage, barMessage); } }
spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ io.markfredchen.custom.starter.config.FooAutoConfiguration
建立 resources/config/foo.properties
spring
foo.fooMessage=Foo! foo.barMessage=Bar!
@SpringBootApplication public class FooApplication { public static void main(String[] args) { SpringApplication.run(FooApplication.class, args); } @Bean public CommandLineRunner runner(final FooService fooService) { return args -> { System.out.println(fooService.getFooMessage()); System.out.println(fooService.getBarMessage()); }; } }
pom.xml
添加如下依賴<dependencies> <dependency> <groupId>io.markfredchen</groupId> <artifactId>foo-spring-boot-starter</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.0.5.RELEASE</version> </dependency> </dependencies>
2018-10-11 11:28:55.457 INFO 23978 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2018-10-11 11:28:55.457 INFO 23978 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2018-10-11 11:28:55.548 INFO 23978 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup 2018-10-11 11:28:55.586 INFO 23978 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2018-10-11 11:28:55.590 INFO 23978 --- [ main] i.m.c.s.foo.application.FooApplication : Started FooApplication in 1.725 seconds (JVM running for 2.44) Foo! Bar!
建立resources/application.properties
json
foo.barMessage=Updated Bar!
2018-10-11 11:28:55.457 INFO 23978 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2018-10-11 11:28:55.457 INFO 23978 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2018-10-11 11:28:55.548 INFO 23978 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup 2018-10-11 11:28:55.586 INFO 23978 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2018-10-11 11:28:55.590 INFO 23978 --- [ main] i.m.c.s.foo.application.FooApplication : Started FooApplication in 1.725 seconds (JVM running for 2.44) Foo! Updated Bar!
建立resources/META-INF/additional-spring-configuration-metadata.json
tomcat
{ "properties": [ { "name": "foo.fooMessage", "type": "java.lang.String", "description": "Foo Message.", "defaultValue": "Foo!" }, { "name": "foo.barMessage", "type": "java.lang.String", "description": "Bar Message.", "defaultValue": "Bar!" } ] }
效果app
本文介紹了spring boot starter機制以及如何建立自定義的starter。starter的目標是對如今有項目進行有效封裝,減小開發人員的重複工做。
完整源代碼訪問GitHub