隨着互聯網技術的發展與不斷創新,以及用戶流量的不斷增大,越來越多的企業項目面臨大數據、高並發等問題,隨之而來的就是通過分布式模型組建架構,微服務思想就集中體現了應用價值,2020 年的你還沒有掌握微服務技術嗎?
本課程會講解 Spring Cloud 的重要知識點同時也會跟隨源碼,與框架設計者共同探索其設計奧妙所在,做到知其然更知其所以然!
實驗介紹
Spring Cloud 是一系列框架的有序集合。它利用 Spring Boot 的開發便利性巧妙地簡化了分布式系統基礎設施的開發。
我們知道,Spring Cloud 整套微服務方案是基於 Spring Boot 作為架構制成的,那么 SpringBootApplication 啟動類作為 Spring Boot 的項目起點,至關重要,本節就了解一下 SpringBootApplication。
知識點
- 自定義 SpringApplication
- 配置 Spring Boot 源
- SpringApplication 類型推斷
- Spring Boot 事件
如何創建一個 Spring Boot 項目
1. Spring 官網創建
如圖所示,在 官網 上快速搭建一個 Spring Boot 項目。
我們可以看到上面可以選擇構建工具、語言、Spring Boot 版本、group 和 artifact 以及依賴。這里我們依據上圖所示的選項進行創建項目,點擊 Generate Project。
2. Maven 命令創建
同樣地,我們也可以使用命令在終端上創建一個項目:
mvn archetype:generate -DgroupId=com.test -DartifactId=demo -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
當我們將新創建后的項目結構展開就會得到:
在我們的環境中已經為大家准備好項目包,同學們執行以下命令便可以把項目下載到 WebIDE 中了。
wget https://labfile.oss.aliyuncs.com/courses/2502/demo.zip && unzip demo.zip
建議同學們直接使用我們的安裝包解壓項目,如果使用命令創建項目的話,在接下來會講解的一些類就需要同學們手動創建了。
如果同學們不清楚詳細的創建過程以及適配環境相關問題,可以先學習 Spring Boot 基礎入門,因為 Spring Boot 是在 Spring 的基礎上建立的。
SpringApplication 的詳細講解
實驗之前,我們首先對新生成的 demo
項目對其做一個調整:將 .mvn 目錄和 .gitignore 目錄以及多余配置項刪除(因為這些配置項目與本次實驗無關),並對配置文件和 pom.xml 文件做一個修改:
- 將 resources 資源目錄下的 application.properties 文件修改為:
# 聲明開放端口號
server.port = 8080
# 聲明項目名稱
spring.application.name = spring-application
最終的效果如圖所示:
完成以上步驟配置,第一個 Spring Boot 項目的創建到這里就基本結束了,接下來我們分析一下 demo
項目中主函數代碼,即在目錄 com.example.demo
就可以查看到啟動類 DemoApplication
:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
這就是最簡化版本的 Spring Boot 啟動類,這里有兩個地方值得我們注意:
一個是類 SpringApplication
,另外一個是注解 @SpringBootApplication
。
Q: 什么是 SpringApplication
?
A: SpringApplication
是 Spring Boot 驅動 Spring 應用上下文的引導類。
Q:怎么理解注解 @SpringBootApplication
?
A:直接查看此注解的源碼,源碼如下:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
}
這里有三個注解值得我們注意:
@ComponentScan
是用於定義掃描的路徑,從中找出標識了需要裝配的類自動裝配到 Spring 的 Bean 容器中。@EnableAutoConfiguration
是激活自動裝配,用於自動載入應用程序所需的所有 Bean。@SpringBootConfiguration
用於標注當前類是配置類,並會將當前類內聲明的一個或多個以@bean
注解標記的方法的實例納入到 Spring 容器中,它與@Configuration
,在功能上是一致的。
Q: 如何理解 @Component
的“派生性”?
A:@Component
是用來把普通 POJO(Plain Ordinary Java Object) 實例化到 Spring 容器中,相當於配置文件中的 <bean id="" class=""/>
,通常我們將 @Component
稱之為元注解。所謂的派生性指的是以元注解為基准,其他注解再次調用元注解而產生的派生。
Spring 之注解編程模型
回顧一下 Spring Boot 中常見的注解,諸如 @Service
、@Repository
、@Controller
、@Configuration
。Spring 在設計的時候,都是引入了 @component
作為這些注解的元注解。
@component
:泛指組件,當組件不好歸類的時候,我們可以使用這個注解進行標注。
@Service
:用於標注業務層組件。
@Component
public @interface Service {
...
}
@Repository
:用於標注數據訪問組件,即 DAO 組件。
@Component
public @interface Repository {
...
}
@Controller
:用於標注控制層組件。
@Component
public @interface Controller {
...
}
@Configuration
:允許通過調用同一類中的其他@Bean
方法來定義 Bean 之間的依賴關系。
@Component
public @interface Configuration {
...
}
Q:關於 Spring 之模式注解(Stereotype Annotations)?
A:所謂的模式注解:@component
邏輯上與 @Service
、@Repository
、@Controller
、@Configuration
都是一樣,只是物理層面上不同,但都是為了找到 BeanDefinition。
現在我們來分析一下,@SpringBootApplication
這個注解,下面是通過源碼顯示的調用關系:
@SpringBootApplication
:引入了@SpringBootConfiguration
注解。
@SpringBootConfiguration
public @interface SpringBootApplication {
...
}
@SpringBootConfiguration
:又引入了@Configuration
注解。
@Configuration
public @interface SpringBootConfiguration {
...
}
@Configuration
:最終引入了@Component
注解。
@Component
public @interface Configuration {
...
}
實際上注解 @SpringBootApplication
會標注當前一些功能。我們知道,注解不能像 Java 類一樣繼承,就通過以上的這樣的方式層層調用。而注解的功能基本相似,我們就把注解的這種特性稱之為派生性。
SpringApplication 啟動類的基本寫法
啟動類 SpringApplication
就是 Spring Boot 應用的引導。
- 最簡化的
SpringApplication
(通過 Spring 官網通過腳手架下載的最簡化的啟動類):
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
- 通過 SpringApplication 增加參數的方式。現在我們在項目目錄
com.test
創建DemoApplication.java
:
package com.test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import java.util.LinkedHashMap;
import java.util.Map;
@SpringBootApplication
public class DemoApplication{
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(DemoApplication.class);
Map<String,Object> properties = new LinkedHashMap<>();
properties.put("server.port",0);
springApplication.setDefaultProperties(properties);
ConfigurableApplicationContext context = springApplication.run(args);
}
SpringApplicationBuilder
方式。現在我們在項目目錄com.test
創建SpringBootEventApplication.java
:
package com.test;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
@SpringBootApplication
public class SpringBootEventApplication{
public static void main(String[] args) {
new SpringApplicationBuilder(SpringBootEventApplication.class) // Fluent API
// 單元測試是 PORT = RANDOM
.properties("server.port=0") // 隨機向 OS 要可用端口
.run(args);
}
- 非 Web 程序方式。現在我們在項目目錄
com.test
創建MicroservicesProjectApplication.java
:
package com.test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import java.util.LinkedHashMap;
import java.util.Map;
@SpringBootApplication
public class MicroservicesProjectApplication {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(DemoApplication.class);
Map<String, Object> properties = new LinkedHashMap<>();
properties.put("server.port", 0);
springApplication.setDefaultProperties(properties);
// 設置為非 web 應用
springApplication.setWebApplicationType(WebApplicationType.NONE);
ConfigurableApplicationContext context = springApplication.run(args);
// 當前 Spring 應用上下文的類:org.springframework.context.annotation.AnnotationConfigApplicationContext
System.out.println("當前 Spring 應用上下文的類:" + context.getClass().getName());
點擊實驗樓新課《Spring Cloud 從入門到實戰》,快開始學習之旅!