01.Spring Boot 之 HelloWorld

1. 環境搭建

代碼已經上傳至 https://github.com/masteryourself-tutorial/tutorial-spring ,詳見 tutorial-spring-boot-core/tutorial-spring-boot-helloworld 工程

1.1 配置文件

1. pom.xml
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.1.4.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<!-- 可以將應用打包成一個可執行的jar包 -->
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>2.1.4.RELEASE</version>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

1.2 代碼

1. HelloWorldApplication
@SpringBootApplication
public class HelloWorldApplication {

    public static void main(String[] args) {
        SpringApplication.run(HelloWorldApplication.class, args);
    }

}
2. HelloWorldController
@RestController
public class HelloWorldController {

    @ResponseBody
    @RequestMapping("/hello")
    public String hello() {
        return "Hello World!";
    }

}

2. 原理分析

2.1 pom.xml 解析

2.1.1 spring-boot-dependencies 依賴分析

項目中引入 spring-boot-dependencies jar 包,這個 jar 包管理了 Spring 用到的所有第三方組件的依賴,因此在 Spring Boot 工程中,只要是被 Spring 管理的組件,都不需要編寫版本號

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.1.4.RELEASE</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

如以下版本號均被管理,更多內容可參考 spring-boot-dependencies

<properties>
    <activemq.version>5.15.9</activemq.version>
    <antlr2.version>2.7.7</antlr2.version>
    <appengine-sdk.version>1.9.73</appengine-sdk.version>
    <artemis.version>2.6.4</artemis.version>
    <aspectj.version>1.9.2</aspectj.version>
    <assertj.version>3.11.1</assertj.version>

    ...

</properties>
2.1.2 spring-boot-starter-web jar 包分析

spring-boot-starter-web 這個 jar 包依賴了 Spring 運行時期的所有 jar 包信息,而且引入了 tomcat-embed-core jar 包,將 tomcat 內置了,所以可以直接通過 main() 方法啓動 web 容器

Spring Boot 依賴圖

2.2 入口類分析

2.2.1 @SpringBootApplication 註解分析

@SpringBootApplication 標註在某個類上就說明這個類是 SpringBoot 的主配置類,它會運該類的 main() 方法來啓動 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 {
1. @SpringBootConfiguration

它表示是一個 SpringBoot 的配置類,作用同 @Configuration,相當於是 Spring 的一個配置文件

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
2. @EnableAutoConfiguration

開啓自動配置功能,這個註解也是個複合註解,它向容器中導入了 AutoConfigurationImportSelector 組件

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

AutoConfigurationImportSelector 實現了 DeferredImportSelector 接口,所以這裏會延時導入,早期版本沒有實現這個接口,那麼就會調用 selectImports() 方法,實現了就會調用 AutoConfigurationGroup#process() 方法

這個方法中有非常重要的一步:getAutoConfigurationMetadata(),即獲取自動配置類的描述信息,它會讀取 META-INF/spring.factories 這個文件中 org.springframework.boot.autoconfigure.EnableAutoConfiguration 對應的值,即所有的自動配置類

讀取配置類的代碼,注意這裏的 SpringFactoriesLoader.loadFactoryNames() 方法就是 spring 自己提供的 SPI 機制,用來獲取 EnableAutoConfiguration 對應的所有實現類,完成自動注入,可以稱得上是整個 Spring Boot 的核心功能

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;
}

META-INF/spring.factories 中的部分配置內容如下,在 spring-boot-autoconfigure-xxx.RELEASE.jar 包下

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.CloudServiceConnectorsAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\

...

@AutoConfigurationPackage 的作用是向容器中導入了 AutoConfigurationPackages.Registrar bean,即自動掃包,它會將主配置類(@SpringBootApplication 標註的類)的所在包及下面所有子包裏面的所有組件掃描到 Spring 容器中

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
3. ComponentScan

添加自定義的掃包規則

主要是排除兩個過濾器:TypeExcludeFilter 和 AutoConfigurationExcludeFilter

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章