上篇文章,咱們聊到了SpringBoot得以實現的幕後推手,此次咱們來用SpringBoot開始HelloWorld之旅。SpringBoot是Spring框架對「約定大於配置(Convention over Configuration)」理念的最佳實踐。SpringBoot應用本質上就是一個基於Spring框架的應用。咱們大多數程序猿已經對Spring特別熟悉了,那隨着咱們的深刻挖掘,會發現SpringBoot中並無什麼新鮮事,若是你不信,那就一塊兒走着瞧唄!html
首先,咱們按照下圖中的步驟生成一個SpringBoot項目:vue
解壓後的項目文件在idea中打開之後,咱們會看到以下的項目結構:java
這時候,咱們在com.hafiz.springbootdemo
包下新建controller
包,而後再在該包下面新建DemoController.java
文件,內容以下:react
package com.hafiz.springbootdemo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/** * @author hafiz.zhang * @description: first spring boot controller * @date Created in 2018/6/3 16:49. */
@RestController
public class DemoController {
@GetMapping("/hello")
public String sayHello(String name) {
return "Hello, " + name;
}
}
而後咱們運行SpringbootDemoApplication.java
這個main方法,啓動成功後,在控制檯中會出現如下日誌,證實項目啓動成功:web
咱們從日誌中能夠看出,已經註冊了get方式的/hello
的路徑以及名爲/error
的路徑,而且項目在tomat中運行在8080端口,而後咱們在瀏覽器中訪問localhost:8080/hello?name=hafiz.zhang
會看到以下信息:redis
這樣咱們就完成了demo項目的開發,先不用這裏面到底發生了啥,我就想問問你:是否是很爽?徹底沒有傳統項目的繁瑣的xml配置,爽到爆有木有?搭建一個項目骨架只要幾秒鐘!這就是SpringBoot帶給咱們的便利~ 就是這麼神奇!就是這麼牛逼!spring
首先咱們來看,生成好的項目中的SpringbootDemoApplication.java
文件,內容以下:json
package com.hafiz.springbootdemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootDemoApplication.class, args);
}
}
代碼很簡單,但最耀眼的就是@SpringBootApplication
註解以及在main方法中運行的SpringAppliation.run()了
,那咱們要揭開SpringBoot應用的奧祕,很明顯就要拿這二位開刀了!瀏覽器
@SpringBootApplication
註解解析先看看@SpringBootApplication
註解的源碼:springboot
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
}
咱們看到@SpringBootApplication
實際上是一個複合的註解,起主要做用的就是@SpringBootConfiguration
、@EnableAutoConfiguration
以及@ComponentScan
三個註解組成,因此若是咱們把SpringBoot啓動類改寫成以下方式,整個SpringBoot應用依然能夠與以前的啓動類功能同樣:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public class SpringbootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootDemoApplication.class, args);
}
}
由於咱們每次新建項目時都要寫上三個註解來完成配置,這顯然太繁瑣了,SpringBoot就爲咱們提供了@SpringBootApplication
這樣一個複合註解來簡化咱們的操做。簡直不能再貼心一點了!
@SpringBootConfiguration
註解解析接着咱們來看@SpringBootConfiguration
註解的源碼:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
咱們能夠看到,這裏面依舊沒有什麼新東西,它SpringBoot爲了區別@Configuration
而新提供的專屬於SpringBoot的註解,功能和@Configuration
如出一轍。而這裏的@Configuration
註解對於咱們來講並不陌生,咱們在上篇文章中進行了詳細的介紹。SpringBoot的啓動類標註了這個註解,毫無疑問,它自己也是個IoC容器的配置類。瞭解到了這裏,咱們其實能夠把SpringBoot的啓動類來拆成兩個類,拆完之後就很是清楚明瞭了:
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class DemoConfiguration {
}
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoConfiguration.class, args);
}
}
因此呢,啓動類DemoApplication其實就是一個標準的Standalone類型的Java程序的main函數啓動類,也並無什麼特殊的東西。
@EnableAutoConfiguration
的神奇之處看到這貨,咱們不只聯想出Spring 中不少以「@Enable」開頭的註解,好比:@EnableScheduling
、@EnableCaching
以及@EnableMBeanExport
等,@EnableAutoConfiguration
註解的理念和工做原理和它們其實一脈相承。簡單的來講,就是該註解藉助@Import
註解的支持,Spring的IoC容器收集和註冊特定場景相關的Bean定義:
@EnableScheduling
是經過@Import
將Spring調度框架相關的bean都加載到IoC容器。@EnableMBeanExport
是經過@Import
將JMX相關的bean定義加載到IoC容器。而@EnableAutoConfiguration
註解也是藉助@Import
將全部複合配置條件的bean定義加載到IoC容器,僅此而已!而@EnableAutoConfiguration
註解的源碼以下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
...
}
這其中最關鍵的就是@Import(EnableAutoConfigurationImportSelector.class)
了,它藉助EnableAutoConfigurationImportSelector.class
能夠幫助SpringBoot應用將全部符合條件的@Configuration配置類都加載到當前SpringBoot建立並使用的IoC容器,就像一個「八爪魚」同樣。
下面咱們給出EnableAutoConfigurationImportSelector.java
的父類AutoConfigurationImportSelector.java
的部分源碼,來解釋和驗證上圖:
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class,
this.beanClassLoader);
}
protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class,
this.beanClassLoader);
}
}
以上源碼能夠看出,@EnableAutoConfiguration
正是藉助SpringFactoriesLoader
的支持,才能完成如此偉大的壯舉!
SpringFactoriesLoader
詳解SpringFactoriesLoader屬於Spring框架專屬的一種擴展方案(其功能和使用方式相似於Java的SPI方案:java.util.ServiceLoader),它的主要功能就是從指定的配置文件META-INF/spring.factories
中加載配置,spring.factories是一個很是經典的java properties文件,內容格式是Key=Value形式,只不過這Key以及Value都很是特殊,爲Java類的完整類名(Fully qualified name),好比:
com.hafiz.service.DemoService=com.hafiz.service.impl.DemoServiceImpl,com.hafiz.service.impl.DemoServiceImpl2
而後Spring框架就能夠根據某個類型做爲Key來查找對應的類型名稱列表了,SpringFactories源碼以下:
public abstract class SpringFactoriesLoader {
private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader){
...
}
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
...
}
// ...
}
對於@EnableAutoConfiguraion
來講,SpringFactoriesLoader的用途和其本意稍微不一樣,它本意是爲了提供SPI擴展,而在@EnableAutoConfiguration
這個場景下,它更多的是提供了一種配置查找的功能的支持,也就是根據@EnableAutoConfiguration
的完整類名org.springframework.boot.autoconfigure.EnableAutoConfiguration
做爲Key來獲取一組對應的@Configuration類:
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.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.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.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.flyway.FlywayAutoConfiguration,\ 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.mustache.MustacheAutoConfiguration,\ org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\ org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\ 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.DispatcherServletAutoConfiguration,\ org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\ org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,\ org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\ org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\ org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\ org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration,\ org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration,\ org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration,\ org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration
在SpringBoot的autoconfigure依賴包中的META-INF文件下的spring.factories文件中,咱們能夠找到以上內容,這就很好的解釋了爲何。
總結來講,@EnableAutoConfiguration
能實現自動配置的原理就是:SpringFactoriesLoader從classpath中搜尋全部META-INF/spring.fatories文件,並將其中Key[org.springframework.boot.autoconfigure.EnableAutoConfiguration
]對應的Value配置項經過反射的方式實例化爲對應的標註了@Configuration
的JavaConfig形式的IoC容器配置類,而後彙總到當前使用的IoC容器中。
@ComponentScan
解析爲何說這個註解是非必需的呢?由於咱們知道做爲Spring框架裏的老成員,@ComponentScan的功能就是自動掃描並加載複合條件的組件或Bean定義,最終將這些bean定義加載到當前使用的容器中。這個過程,咱們能夠手工單個進行註冊,不是必定要經過這個註解批量掃描和註冊,因此說@ComponentScan
是非必需的。
因此,若是咱們當前應用沒有任何bean定義須要經過@ComponentScan
加載到當前SpringBoot應用對應的IoC容器,那麼,去掉@ComponentScan
註解,當前的SpringBoot應用依舊能夠完美運行!那是否是到目前爲止,依舊沒有什麼新鮮的事物出現?
@RestController
以及@GetMapping
@RestController
註解也是一個複合註解,沒啥新東西,就是自動返回json類型的數據,源碼以下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
String value() default "";
}
@GetMapping
註解也是一個複合註解,依舊沒啥新東西,就是用來定義只支持GET請求的URL,源碼以下:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.GET)
public @interface GetMapping {
...
}
剛開始沒有深刻接觸SpringBoot的時候,感受這貨真的好神奇,居然能夠省去那麼多搭建步驟。這特麼簡直就是開發人員的福音啊,再回頭想一想這貨爲啥會火呢?咱們都知道近幾年微服務的概念很火,不少企業也開始把本身的項目作成微服務了,那隨着項目愈來愈多,按照咱們之前那種方式配置項目,很繁瑣,光建立項目就要耗費很大的精力和時間,這個時候拯救世界的SpringBoot出現了,它簡化了配置方式,實乃應運而生,順勢而爲啊!再不火,沒天理不是。下篇文章咱們來聊一聊SpringBoot的啓動流程。期待的小夥伴,評論扣1.