導航:首頁 > 源碼編譯 > springboot解剖源碼

springboot解剖源碼

發布時間:2022-11-02 17:27:37

❶ boot自動配置的原理

Spring Boot是基於Spring開發的,是約定大於配置的核心思想。並且集成了大量的第三方庫配置比如redis、mongoDB、jpa等。Spring Boot就相當於maven整合了所有jar包,Spring Boot整合了所有框架。其設計目的是用來簡化新 Spring 應用的初始搭建以及開發過程,並不少什麼新的框架。

二、Spring Boot優點

優點其實就是簡單、快速

快速創建獨立運行的Spring項目以及主流框架集成
使用嵌入式的server容器,應用無需打成WAR包
starters自動依賴與版本控制
有大量的自動配置,簡化開發
准生產環境運行應用監控
與雲計算的天然集成
Spring Boot主程序分析

//@SpringBootApplication標注這個類是一個Springboot的應用@{publicstaticvoidmain(String[] args){//將Springboot應用啟動 SpringApplication.run(Springboot02DemoApplication.class, args);}}

SpringBootApplication源碼剖析,進入源碼,結果發現其實它是一個組合註解

第一個SpringBootConfiguration註解:@SpringBootConfiguration-->是Spring Boot配置類。下面有一個叫@Configuration:它是配置類,下面又有@Component,其實它就是一個注入組件。

第二個@EnableAutoConfiguration註解:是開啟自配配置功能

@AutoConfigurationPackage//自動配置包
@Import(.class)
public @interface EnableAutoConfiguration {}

@AutoConfigurationPackage:自動配置包,使用@Import(.class)註解來完成的,它是spring boot底層註解,作用是給容器中導入組件。

自動配置原理

(1)Spring Boot啟動的時候首先載入主配置類,開啟啦自動配置的功能(@EnableAutoConfiguration)

(2)自動配置功能@EnableAutoConfiguration的作用:它是利用了

@Import(.class)給容器中導入一些組件。那麼,他會給我們導入哪些組件呢?進入源碼看一下部分源碼如下。

//@EnableAutoConfiguration註解
@AutoConfigurationPackage
/@Import(.class)
public @interface EnableAutoConfiguration

@Import(.class)自動配置導入選擇

public class implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
//----部分源碼省略----//
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
//----部分源碼省略----//
}

❷ 什麼是Spring Boot

Spring Boot 可以輕松創建獨立的、生產級的基於 Spring 的應用程序,您可以「直接運行」這些應用程序。

我們對 Spring 平台和第三方庫採取了固執的觀點,因此您可以輕松上手。大多數 Spring Boot 應用程序需要最少的 Spring 配置。

Spring中國教育管理中心

特徵

了解更多,可查詢Spring中國教育管理中心相關信息

❸ Spring Boot 自動化配置原理帶圖全面講解

# Spring Boot 自動化配置原理

> 我們經常使用Spring Boot,是否知道Spring Boot自動化配置是怎麼實現的呢?

<a name="iM87x"></a>

## 一 初識自動化配置

Spring Boot自動化配置依賴於@EnableAutoConfiguration註解<br />該註解會在@SpringBootApplication中包含<br />該註解為一個復合註解包含了以下註解<br />@SpringBootConfiguration 標識該類是一個配置類<br />@EnableAutoConfiguration 開啟自動化配置<br />@ComponentScan 掃描該類下的所有包配置的bean<br />![](https://cdn.nlark.com/yuque/0/2020/png/1751881/1605766349305-e5b2ae88-5100-4f06-9012-359fb970484b.png#align=left&display=inline&height=233&margin=%5Bobject%20Object%5D&name=&originHeight=466&originWidth=916&size=60525&status=done&style=none&width=458)

<a name="TI8GH"></a>

## 二 揭開自動化配置面紗

**@EnableAutoConfiguratio**n 今天我們主要關注的是這個註解 <br />此註解為一個復合註解包含了<br />**@AutoConfigurationPackage **<br />該註解會導入一個**AutoConfigurationPackages**類<br />![](https://cdn.nlark.com/yuque/0/2020/png/1751881/1605774036383-146af0c9-a623-4b10-8b73-07c4b649c5b4.png#align=left&display=inline&height=227&margin=%5Bobject%20Object%5D&name=&originHeight=454&originWidth=1019&size=50537&status=done&style=none&width=509.5)<br />**該方法****將主程序類所在包及所有子包下的組件到掃描到spring容器中完成****項目包下組件的自動注冊**

> **至此我們完成了自動化配置中自己的組件的自動化配置,那麼我們依賴的jar包自動化配置說怎麼實現的呢,請繼續往下看**

![](https://cdn.nlark.com/yuque/0/2020/png/1751881/1605775088571-79912d2c-5d1d-4d65-969c-85d29fdbf315.png#align=left&display=inline&height=299&margin=%5Bobject%20Object%5D&name=&originHeight=598&originWidth=1814&size=127855&status=done&style=none&width=907)<br />![](https://cdn.nlark.com/yuque/0/2020/png/1751881/1605775171339-f9ee7973-5264-4bcc-9296-d6dfcf93d278.png#align=left&display=inline&height=284&margin=%5Bobject%20Object%5D&name=&originHeight=568&originWidth=1003&size=78791&status=done&style=none&width=501.5)

<a name="mz1Pw"></a>

## 三 深入自動化配置

**我們繼續回到****EnableAutoConfiguration****註解 **<br />**![](https://cdn.nlark.com/yuque/0/2020/png/1751881/1605777120808-058819b5-b772-4c66-a500-640a2bb839da.png#align=left&display=inline&height=374&margin=%5Bobject%20Object%5D&name=&originHeight=749&originWidth=733&size=64165&status=done&style=none&width=366.5)**

<a name="iHhrI"></a>

### 該註解包含2個屬性:

exclude:根據類排除不使用的自動配置;<br />excludeName:根據類名排除不使用的自動配置;<br />並導入了****類 該類的核心方法為**getCandidateConfigurations**通過該方法即可獲取到(spring-boot-2.1.3.RELEASE.jar/META-INF/spring.factories) 下的配置文件,該文件為spring boot自動化配置的配置文件,至此我們獲取到的是所有的自動化配置類,那麼spring boot的按需導入是怎麼實現的呢,請繼續往下看<br />![](https://cdn.nlark.com/yuque/0/2020/png/1751881/1605776345938-dfe94697-90f9-4c97-97d9-c557f5ca3a1f.png#align=left&display=inline&height=328&margin=%5Bobject%20Object%5D&name=&originHeight=655&originWidth=1284&size=93261&status=done&style=none&width=642)<br />![](https://cdn.nlark.com/yuque/0/2020/png/1751881/1605776688829-6f621201-ffda-419d-bb1c-f36d6d314ee3.png#align=left&display=inline&height=424&margin=%5Bobject%20Object%5D&name=&originHeight=848&originWidth=1668&size=180815&status=done&style=none&width=834)<br />![](https://cdn.nlark.com/yuque/0/2020/png/1751881/1605776722465-56b97643-9223-4bcc-b05c-d4a40031ec43.png#align=left&display=inline&height=437&margin=%5Bobject%20Object%5D&name=&originHeight=873&originWidth=1573&size=201935&status=done&style=none&width=786.5)<br />![](https://cdn.nlark.com/yuque/0/2020/png/1751881/1605777393268-9c7a8c52-9e1e-4665-999a-44a68b5bffff.png#align=left&display=inline&height=239&margin=%5Bobject%20Object%5D&name=&originHeight=478&originWidth=1038&size=95520&status=done&style=none&width=519)<br /><br />因為spring boot是按需配置所以我們還需要根據引入的依賴篩選出需要的配置,核心方法如下

```java

protected AutoConfigurationEntry getAutoConfigurationEntry(

AutoConfigurationMetadata autoConfigurationMetadata,

AnnotationMetadata annotationMetadata) {

        //判斷是否開啟自動配置

if (!isEnabled(annotationMetadata)) {

return EMPTY_ENTRY;

}

AnnotationAttributes attributes = getAttributes(annotationMetadata);

      //獲取自動配置文件和配置

List<String> configurations = getCandidateConfigurations(annotationMetadata,

attributes);

        //刪除重復項

configurations = removeDuplicates(configurations);

        //獲取排除的自動化配置

Set<String> exclusions = getExclusions(annotationMetadata, attributes);

        //檢查排除的自動化配置

checkExcludedClasses(configurations, exclusions);

      //移除排除的自動化配置

configurations.removeAll(exclusions);

      //根據引入的依賴按需導入自動配置

configurations = filter(configurations, autoConfigurationMetadata);

        //觸發自動化配置

(configurations, exclusions);

return new AutoConfigurationEntry(configurations, exclusions);

}

```

filter方法會過濾我們的自動化配置類 ,規則是根據我們配置類上的  @Conditiona系列註解<br />![](https://cdn.nlark.com/yuque/0/2020/png/1751881/1605779980417-f5d8e3cc-3a9e-4dac-bc3e-328d40b8b9eb.png#align=left&display=inline&height=246&margin=%5Bobject%20Object%5D&name=&originHeight=491&originWidth=1254&size=80896&status=done&style=none&width=627)

> @Conditiona系列註解含義,將在明天給大家講解,明天會做一個自動配置的例子 希望大家關注一下

❹ Spring Boot 配置的優先順序

本文主要參考 Externalized Configuration
為了能讓應用在不同的環境下運行,Spring Boot允許自定義配置文件,如properties文件、yaml文件、系統環境變數參數、命令行參數。配置文件的覆蓋優先順序如下

Developer Tools 提供了一些開發幫助工具,在build.gradle添加依賴後啟用。

Spring Boot會讀取在計算機用戶的home目錄下的 .spring-boot-devtools.properties 文件里的配置參數到該計算級的所有Spring Boot應用中作為頂層配置,如Linux環境下root用戶下 ~/.spring-boot-devtools.properties 文件。開發過程中,可以將一些個人參數記錄在這個配置文件中,例如ip地址,機器uuid,datasource參數等。在該配置文件中的定義的配置環境並不會影響到應用配置的讀取,官方原話是:

但要注意,該配置優先順序最高,設置的時候需要做好記錄否則會出現"原因不明的bug",不過應該很少人會用到這個功能。分析下源碼,就是加了一個配置切面,並把其設置為頂層配置:

在測試的時候,可能會使用另一套測試專用的配置,該套配置的優先順序高於系統環境變數、java系統參數、程序內部參數, @TestPropertySource 註解就是用來指定這一類配置的。該註解一共有5個參數可以設置:

如果使用註解的時候沒有任何參數,那麼會從標注了註解的測試類的包中嘗試讀取配置文件,例如測試類 com.spring.test.DemoTest ,那麼相應的默認配置文件為 com.spring.test.DemoTest.properties ,如果沒有找到默認的配置文件則拋出非法狀態異常。
在初始化上下文的時候會調用一個讀取、合並配置的方法 ,該方法通過工具類 TestPropertySourceUtils 讀取類的註解信息。 TestPropertySourceUtils 從類的註解解析配置信息後返回一個可合並的配置源。

@SpringBootTest 的value\properties屬性用於注入一些自定義的註解,語法要求和 @TestPropertySource 的properties一樣,這里就不詳細展開了。

用命令行方式啟動Spring Boot應用程序的時候,可以注入一些配置參數,參數的格式是 --key=name 。舉個簡單的例子,程序直接輸出一個參數,然後打成jar包後運行。

運行:
java -jar .\springbootconfiguraiton.jar --cl.name="Spring Boot Arguments"
從輸出的結果中可以看到可以讀取到命令行中的配置。

可以在環境變數中定義一個key為SPRING_APPLICATION_JSON的參數,值為json字元串,Spring Boot會解析該json字元串作為參數注入到系統中。SPRING_APPLICATION_JSON可以定義在環境變數、系統配置中,命令行也是可以的,例如命令行參數中用到的demo,執行以下的命令也應該能得到相同的參數結果。
java -jar .\springbootconfiguraiton.jar SPRING_APPLICATION_JSON='{"cl":{"name"="Spring Boot Arguments"}}'
結果輸出是undefined,不知道原因,這個配置方式用的應該也很少,放棄研究。。。

優先順序是 ServletConfig > ServletContext ,可以在application.yml中設置:

隨機數配置大多用於測試,支持的類型如下:

其中long\int可以限制數據范圍,[]是閉區間,()是開區間。

這個應該是我們用的最多的。首先說優先順序,文件可以放在以下4個位置,相同文件從上到下覆蓋。外部指的是啟動應用程序的目錄,例如gradle用application插件打包後,運行的腳本目錄就是 ./ :

文件的命名為 application-[當前激活的環境名].[yml/properties] ,當前激活的配置可以用 spring.profile.active=[當前激活的環境名] 定義,多個環境名用逗號分隔,未設置時用 default 標識。關於如果修改默認的載入路徑和文件名,後面會繼續討論。

Spring Boot系統啟動時默認會讀取的配置文件,支持properties\yml格式。也就是說,會先載入 application.properties ,根據 spring.profile.active 的設置載入相應的 application-XX.properties 配置,然後按優先順序合並配置文件。
不同文件目錄下application.properties的優先順序和 自定義配置文件 的順序是一樣的。

類似 @TestPropertySource註解 ,在項目中可以方便的注入自定義的配置文件,註解一共有5個參數:

❺ springboot快速入門及@SpringBootApplication註解分析

簡單demo
使用 maven 構建項目,官方現在穩定版本是1.5.4,第一個入門demo不是web項目,pom依賴如下:

實體 User 類:

配置類:

入口類 Application :

項目結構目錄

啟動程序,以 main 方法啟動:

列印出正確的結果。

來分析一下流程,為何 Runnable 類, User , Map 會納入spring容器。

首先我們分析的就是入口類 Application 的啟動註解 @SpringBootApplication ,進入源碼:

發現 @SpringBootApplication 是一個復合註解,包括 @ComponentScan ,和 @SpringBootConfiguration , @EnableAutoConfiguration 。

根據上面的理解,上面的入口類 Application ,我們可以使用:

使用 @ComponentScan 註解代替 @SpringBootApplication 註解,也可以正常運行程序。原因是 @SpringBootApplication 中包含 @ComponentScan ,並且 springboot 會將入口類看作是一個 @SpringBootConfiguration 標記的配置類,所以定義在入口類 Application 中的 Runnable 也可以納入到容器管理。

看一個demo學會使用這些參數配置
在包下com.hao.miao.springboot定義一個啟動應用類(加上@SpringBootApplication註解)

在com.hao.miao.beans包下定義一個實體類,並且想將其納入到spring容器中,

啟動啟動類,列印結果如下:

說明Cat類並沒有納入到spring容器中,這個結果也如我們所想,因為@SpringBootApplication只會掃描@SpringBootApplication註解標記類包下及其子包的類(特定註解標記,比如說@Controller,@Service,@Component,@Configuration和@Bean註解等等)納入到spring容器,很顯然MyConfig不在@SpringBootApplication註解標記類相同包下及其子包的類,所以需要我們去配置一下掃包路徑。

修改啟動類,@SpringBootApplication(scanBasePackages = "com.hao.miao"),指定掃描路徑:

啟動並列印:

當然使用@SpringBootApplication(scanBasePackageClasses = MyConfig.class),指定scanBasePackageClasses參數的value值是你需要掃描的類也可以,結果一樣,不過如果多個配置類不在當前包及其子包下,則需要指定多個。

再看一個列子,
在上面的列子的相同包下(com.hao.miao.springboot)配置了People,並將其納入到spring容器中(@Component),我們知道@SpringBootApplication註解會掃描當前包及其子包,所以People類會納入到spring容器中去,我們需要將其排除在spring容器中,如何操作?
可以使用@SpringBootApplication的另外二個參數(exclude或excludeName)

啟動類,

啟動並列印結果:

然後修改@SpringBootApplication配置,

很明顯啟動報錯。使用@excludeName註解也可以。如下,
@SpringBootApplication(excludeName = {"com.hao.miao.springboot.People"})

參考文檔:
Springboot1.5.4官方文檔

❻ Spring Boot 最核心的 25 個註解,都是干貨!

Spring Boot 最核心的 25 個註解
1、@SpringBootApplication

這是 Spring Boot 最最最核心的註解,用在 Spring Boot 主類上,標識這是一個 Spring Boot 應用,用來開啟 Spring Boot 的各項能力。

其實這個註解就是 @SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan 這三個註解的組合,也可以用這三個註解來代替 @SpringBootApplication 註解。

2、@EnableAutoConfiguration

允許 Spring Boot 自動配置註解,開啟這個註解之後,Spring Boot 就能根據當前類路徑下的包或者類來配置 Spring Bean。

如:當前類路徑下有 Mybatis 這個 JAR 包,MybatisAutoConfiguration 註解就能根據相關參數來配置 Mybatis 的各個 Spring Bean。

3、@Configuration

這是 Spring 3.0 添加的一個註解,用來代替 applicationContext.xml 配置文件,所有這個配置文件裡面能做到的事情都可以通過這個註解所在類來進行注冊。

4、@SpringBootConfiguration

這個註解就是 @Configuration 註解的變體,只是用來修飾是 Spring Boot 配置而已,或者可利於 Spring Boot 後續的擴展。

5、@ComponentScan

這是 Spring 3.1 添加的一個註解,用來代替配置文件中的 component-scan 配置,開啟組件掃描,即自動掃描包路徑下的 @Component 註解進行注冊 bean 實例到 context 中。

前面 5 個註解可以在這篇文章《Spring Boot 最核心的 3 個註解詳解》中了解更多細節的。

6、@Conditional

這是 Spring 4.0 添加的新註解,用來標識一個 Spring Bean 或者 Configuration 配置文件,當滿足指定的條件才開啟配置。

7、@ConditionalOnBean

組合 @Conditional 註解,當容器中有指定的 Bean 才開啟配置。

8、@ConditionalOnMissingBean

組合 @Conditional 註解,和 @ConditionalOnBean 註解相反,當容器中沒有指定的 Bean 才開啟配置。

9、@ConditionalOnClass

組合 @Conditional 註解,當容器中有指定的 Class 才開啟配置。

10、@ConditionalOnMissingClass

組合 @Conditional 註解,和 @ConditionalOnMissingClass 註解相反,當容器中沒有指定的 Class 才開啟配置。

11、@ConditionalOnWebApplication

組合 @Conditional 註解,當前項目類型是 WEB 項目才開啟配置。

當前項目有以下 3 種類型。

enum Type {

}

12、@

組合 @Conditional 註解,和 @ConditionalOnWebApplication 註解相反,當前項目類型不是 WEB 項目才開啟配置。

13、@ConditionalOnProperty

組合 @Conditional 註解,當指定的屬性有指定的值時才開啟配置。

14、@ConditionalOnExpression

組合 @Conditional 註解,當 SpEL 表達式為 true 時才開啟配置。

15、@ConditionalOnJava

組合 @Conditional 註解,當運行的 Java JVM 在指定的版本范圍時才開啟配置。

16、@ConditionalOnResource

組合 @Conditional 註解,當類路徑下有指定的資源才開啟配置。

17、@ConditionalOnJndi

組合 @Conditional 註解,當指定的 JNDI 存在時才開啟配置。

18、@ConditionalOnCloudPlatform

組合 @Conditional 註解,當指定的雲平台激活時才開啟配置。

19、@ConditionalOnSingleCandidate

組合 @Conditional 註解,當指定的 class 在容器中只有一個 Bean,或者同時有多個但為首選時才開啟配置。

20、@ConfigurationProperties

用來載入額外的配置(如 .properties 文件),可用在 @Configuration 註解類,或者 @Bean 註解方法上面。

21、@EnableConfigurationProperties

一般要配合 @ConfigurationProperties 註解使用,用來開啟對 @ConfigurationProperties 註解配置 Bean 的支持。

22、@AutoConfigureAfter

用在自動配置類上面,表示該自動配置類需要在另外指定的自動配置類配置完之後。

如 Mybatis 的自動配置類,需要在數據源自動配置類之後。

23、@AutoConfigureBefore

這個和 @AutoConfigureAfter 註解使用相反,表示該自動配置類需要在另外指定的自動配置類配置之前。

24、@Import

這是 Spring 3.0 添加的新註解,用來導入一個或者多個 @Configuration 註解修飾的類,這在 Spring Boot 裡面應用很多。

25、@ImportResource

這是 Spring 3.0 添加的新註解,用來導入一個或者多個 Spring 配置文件,這對 Spring Boot 兼容老項目非常有用,因為有些配置無法通過 Java Config 的形式來配置就只能用這個註解來導入。

歡迎Java工程師朋友們加入Java高並發: 957734884 ,群內提供免費的Java架構學習資料(裡面有高可用、高並發、高性能及分布式、Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間「來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!

❼ SpringBoot核心原理:自動配置、事件驅動、Condition

SpringBoot是Spring的包裝,通過自動配置使得SpringBoot可以做到開箱即用,上手成本非常低,但是學習其實現原理的成本大大增加,需要先了解熟悉Spring原理。

如果還不清楚Spring原理的,可以先查看博主之前的文章,本篇主要分析SpringBoot的啟動、自動配置、Condition、事件驅動原理。

SpringBoot啟動非常簡單,因其內置了Tomcat,所以只需要通過下面幾種方式啟動即可:

可以看到第一種是最簡單的,也是最常用的方式,需要注意類上面需要標注 @SpringBootApplication 註解,這是自動配置的核心實現,稍後分析,先來看看SpringBoot啟動做了些什麼?

在往下之前,不妨先猜測一下,run方法中需要做什麼?對比Spring源碼,我們知道,Spring的啟動都會創建一個 ApplicationContext 的應用上下文對象,並調用其refresh方法啟動容器,SpringBoot只是Spring的一層殼,肯定也避免不了這樣的操作。

另一方面,以前通過Spring搭建的項目,都需要打成War包發布到Tomcat才行,而現在SpringBoot已經內置了Tomcat,只需要打成Jar包啟動即可,所以在run方法中肯定也會創建對應的Tomcat對象並啟動。以上只是我們的猜想,下面就來驗證,進入run方法:

SpringBoot的啟動流程就是這個方法,先看 getRunListeners 方法,這個方法就是去拿到所有的 SpringApplicationRunListener 實現類,這些類是用於SpringBoot事件發布的,關於事件驅動稍後分析,這里主要看這個方法的實現原理:

一步步追蹤下去可以看到最終就是通過SPI機制根據介面類型從 META-INF/spring.factories 文件中載入對應的實現類並實例化,SpringBoot的自動配置也是這樣實現的。

為什麼要這樣做呢?通過註解掃描不可以么?當然不行,這些類都在第三方jar包中,註解掃描實現是很麻煩的,當然你也可以通過 @Import 註解導入,但是這種方式不適合擴展類特別多的情況,所以這里採用SPI的優點就顯而易見了。

回到run方法中,可以看到調用了 createApplicationContext 方法,見名知意,這個就是去創建應用上下文對象:

注意這里通過反射實例化了一個新的沒見過的上下文對象 ,這個是SpringBoot擴展的,看看其構造方法:

如果你有看過Spring註解驅動的實現原理,這兩個對象肯定不會陌生,一個實支持註解解析的,另外一個是掃描包用的。

上下文創建好了,下一步自然就是調用refresh方法啟動容器:

這里首先會調用到其父類中 :

可以看到是直接委託給了父類:

這個方法不會陌生吧,之前已經分析過了,這里不再贅述,至此SpringBoot的容器就啟動了,但是Tomcat啟動是在哪裡呢?run方法中也沒有看到。

實際上Tomcat的啟動也是在refresh流程中,這個方法其中一步是調用了onRefresh方法,在Spring中這是一個沒有實現的模板方法,而SpringBoot就通過這個方法完成了Tomcat的啟動:

這里首先拿到 TomcatServletWebServerFactory 對象,通過該對象再去創建和啟動Tomcat:

上面的每一步都可以對比Tomcat的配置文件,需要注意默認只支持了http協議:

如果想要擴展的話則可以對 additionalTomcatConnectors 屬性設置值,需要注意這個屬性沒有對應的setter方法,只有 addAdditionalTomcatConnectors 方法,也就是說我們只能通過實現 BeanFactoryPostProcessor 介面的 postProcessBeanFactory 方法,而不能通過 的 方法,因為前者可以通過傳入的BeanFactory對象提前獲取到 TomcatServletWebServerFactory 對象調用 addAdditionalTomcatConnectors 即可;而後者只能拿到BeanDefinition對象,該對象只能通過setter方法設置值。

這段代碼會在控制台列印所有的事件名稱,按照順序如下:

以上是正常啟動關閉,如果發生異常還有發布 ApplicationFailedEvent 事件。事件的發布遍布在整個容器的啟動關閉周期中,事件發布對象剛剛我們也看到了是通過SPI載入的 SpringApplicationRunListener 實現類 EventPublishingRunListener ,同樣事件監聽器也是在 spring.factories 文件中配置的,默認實現了以下監聽器:

可以看到有用於文件編碼的( ),有載入日誌框架的( LoggingApplicationListener ),還有載入配置的( ConfigFileApplicationListener )等等一系列監聽器,SpringBoot也就是通過這系列監聽器將必要的配置和組件載入到容器中來,這里不再詳細分析,感興趣的讀者可以通過其實現的 onApplicationEvent 方法看到每個監聽器究竟是監聽的哪一個事件,當然事件發布和監聽我們自己也是可以擴展的。

SpringBoot最核心的還是自動配置,為什麼它能做到開箱即用,不再需要我們手動使用 @EnableXXX 等註解來開啟?這一切的答案就在 @SpringBootApplication 註解中:

這里重要的註解有三個: @SpringBootConfiguration 、 @EnableAutoConfiguration 、 @ComponentScan 。 @ComponentScan 就不用再說了, @SpringBootConfiguration 等同於 @Configuration ,而 @EnableAutoConfiguration 就是開啟自動配置:

@AutoConfigurationPackage 註解的作用就是將該註解所標記類所在的包作為自動配置的包,簡單看看就行,主要看 ,這個就是實現自動配置的核心類,注意這個類是實現的 DeferredImportSelector 介面。

在這個類中有一個 selectImports 方法。這個方法在我之前的文章這一次搞懂Spring事務註解的解析也有分析過,只是實現類不同,它同樣會被 類調用,先來看這個方法做了些什麼:

追蹤源碼最終可以看到也是從 META-INF/spring.factories 文件中拿到所有 EnableAutoConfiguration 對應的值(在 spring-boot-autoconfigure 中)並通過反射實例化,過濾後包裝成 AutoConfigurationEntry 對象返回。

看到這里你應該會覺得自動配置的實現就是通過這個 selectImports 方法,但實際上這個方法通常並不會被調用到,而是會調用該類的內部類 AutoConfigurationGroup 的process和selectImports方法,前者同樣是通過 getAutoConfigurationEntry 拿到所有的自動配置類,而後者這是過濾排序並包裝後返回。

下面就來分析 是怎麼調用到這里的,直接進入 processConfigBeanDefinitions 方法:

前面一大段主要是拿到合格的 Configuration 配置類,主要邏輯是在 ConfigurationClassParser.parse 方法中,該方法完成了對 @Component 、 @Bean 、 @Import 、 @ComponentScans 等註解的解析,這里主要看對 @Import 的解析,其它的讀者可自行分析。一步步追蹤,最終會進入到 processConfigurationClass 方法:

這里需要注意 this.conditionEvaluator.shouldSkip 方法的調用,這個方法就是進行Bean載入過濾的,即根據 @Condition 註解的匹配值判斷是否載入該Bean,具體實現稍後分析,繼續跟蹤主流程 doProcessConfigurationClass :

這里就是完成對一系列註解的支撐,我省略掉了,主要看 processImports 方法,這個方法就是處理 @Import 註解的:

剛剛我提醒過 是實現 DeferredImportSelector 介面的,如果不是該介面的實現類則是直接調用 selectImports 方法,反之則是調用 DeferredImportSelectorHandler.handle 方法:

首先創建了一個 DeferredImportSelectorHolder 對象,如果是第一次執行則是添加到 deferredImportSelectors 屬性中,等到 ConfigurationClassParser.parse 的最後調用process方法:

反之則是直接執行,首先通過register拿到 AutoConfigurationGroup 對象:

然後在 processGroupImports 方法中進行真正的處理:

在 getImports 方法中就完成了對process和 selectImports 方法的調用,拿到自動配置類後再遞歸調用調用 processImports 方法完成對自動配置類的載入。至此,自動配置的載入過程就分析完了,下面是時序圖:

在自動配置類中有很多Condition相關的註解,以AOP為例:

這里就能看到 @ConditionalOnProperty 、 @ConditionalOnClass 、 @ConditionalOnMissingClass ,另外還有 @ConditionalOnBean 、 @ConditionalOnMissingBean 等等很多條件匹配註解。

這些註解表示條件匹配才會載入該Bean,以 @ConditionalOnProperty 為例,表明配置文件中符合條件才會載入對應的Bean,prefix表示在配置文件中的前綴,name表示配置的名稱, havingValue 表示配置為該值時才匹配, matchIfMissing 則是表示沒有該配置是否默認載入對應的Bean。其它註解可類比理解記憶,下面主要來分析該註解的實現原理。

這里註解點進去看會發現每個註解上都標注了 @Conditional 註解,並且value值都對應一個類,比如 OnBeanCondition ,而這些類都實現了 Condition 介面,看看其繼承體系:

上面只展示了幾個實現類,但實際上Condition的實現類是非常多的,我們還可以自己實現該介面來擴展 @Condition 註解。Condition介面中有一個matches方法,這個方法返回true則表示匹配。該方法在 ConfigurationClassParser 中多處都有調用,也就是剛剛我提醒過的shouldSkip方法,具體實現是在 ConditionEvaluator 類中:

再來看看matches的實現,但 OnBeanCondition 類中沒有實現該方法,而是在其父類 SpringBootCondition 中:

getMatchOutcome 方法也是一個模板方法,具體的匹配邏輯就在這個方法中實現,該方法返回的 ConditionOutcome 對象就包含了是否匹配和日誌消息兩個欄位。進入到 OnBeanCondition 類中:

可以看到該類支持了 @ConditionalOnBean 、 @ConditionalOnSingleCandidate 、 @ConditionalOnMissingBean 註解,主要的匹配邏輯在 getMatchingBeans 方法中:

這里邏輯看起來比較復雜,但實際上就做了兩件事,首先通過 getNamesOfBeansIgnoredByType 方法調用 beanFactory.getBeanNamesForType 拿到容器中對應的Bean實例,然後根據返回的結果判斷哪些Bean存在,哪些Bean不存在(Condition註解中是可以配置多個值的)並返回MatchResult對象,而MatchResult中只要有一個Bean沒有匹配上就返回false,也就決定了當前Bean是否需要實例化。

本篇分析了SpringBoot核心原理的實現,通過本篇相信讀者也將能更加熟練地使用和擴展SpringBoot。

另外還有一些常用的組件我沒有展開分析,如事務、MVC、監聽器的自動配置,這些我們有了Spring源碼基礎的話下來看一下就明白了,這里就不贅述了。

最後讀者可以思考一下我們應該如何自定義starter啟動器,相信看完本篇應該難不倒你。

❽ spring boot原理

前端常使用模板引擎,主要有FreeMarker和Thymeleaf,它們都是用Java語言編寫的,渲染模板並輸出相應文本,使得界面的設計與應用的邏輯分離,同時前端開發還會使用到Bootstrap、AngularJS、JQuery等;

在瀏覽器的數據傳輸格式上採用Json,非xml,同時提供RESTfulAPI;SpringMVC框架用於數據到達伺服器後處理請求;到數據訪問層主要有Hibernate、MyBatis、JPA等持久層框架;資料庫常用MySQL;開發工具推薦IntelliJIDEA。

(8)springboot解剖源碼擴展閱讀:

SpringBoot所具備的特徵有:

(1)可以創建獨立的Spring應用程序,並且基於其Maven或Gradle插件,可以創建可執行的JARs和WARs;

(2)內嵌Tomcat或Jetty等Servlet容器;

(3)提供自動配置的「starter」項目對象模型(POMS)以簡化Maven配置;

(4)盡可能自動配置Spring容器;

(5)提供准備好的特性,如指標、健康檢查和外部化配置;

(6)絕對沒有代碼生成,不需要XML配置。

Spring的初衷:

1、JAVA EE開發應該更加簡單。

2、使用介面而不是使用類,是更好的編程習慣。Spring將使用介面的復雜度幾乎降低到了零。

3、為JavaBean提供了一個更好的應用配置框架。

4、更多地強調面向對象的設計,而不是現行的技術如JAVA EE。

5、盡量減少不必要的異常捕捉。

6、使應用程序更加容易測試。

❾ [Spring boot源碼解析] 2 啟動流程分析

在了解 Spring Boot 的啟動流程的時候,我們先看一下一個Spring Boot 應用是如何啟動的,如下是一個簡單的 SpringBoot 程序,非常的簡潔,他是如何做到的呢,我們接下來就將一步步分解。

我們追蹤 SpringApplication.run() 方法,其實最終它主要的邏輯是新建一個 SpringApplication ,然後調用他的 run 方法,如下:

我們先來看一下創建 SpringApplication 的方法:

在將Main class 設置 primarySources 後,調用了 WebApplicationType.deceFromClasspath() 方法,該方法是為了檢查當前的應用類型,並設置給 webApplicationType 。 我們進入 deceFromClasspath 方法 :

這里主要是通過類載入器判斷是否存在 REACTIVE 相關的類信息,假如有就代表是一個 REACTIVE 的應用,假如不是就檢查是否存在 Servelt 和 ,假如都沒有,就代表應用為非 WEB 類應用,返回 NONE ,默認返回 SERVLET 類型,我們這期以我們目前最常使用的 SERVLET 類型進行講解,所以我們在應用中引入了 spring-boot-starter-web 作為依賴:

他會包含 Spring-mvc 的依賴,所以就包含了內嵌 tomcat 中的 Servlet 和 Spring-web 中的 ,因此返回了 SERVLET 類型。

回到剛才創建 SpringApplication 的構建方法中,我們設置完成應用類型後,就尋找所有的 Initializer 實現類,並設置到 SpringApplication 的 Initializers 中,這里先說一下 getSpringFactoriesInstances 方法,我們知道在我們使用 SpringBoot 程序中,會經常在 META-INF/spring.factories 目錄下看到一些 EnableAutoConfiguration ,來出發 config 類注入到容器中,我們知道一般一個 config 類要想被 SpringBoot 掃描到需要使用 @CompnentScan 來掃描具體的路徑,對於 jar 包來說這無疑是非常不方便的,所以 SpringBoot 提供了另外一種方式來實現,就是使用 spring.factories ,比如下面這個,我們從 Springboot-test 中找到的例子,這里先定義了一個ExampleAutoConfiguration,並加上了 Configuration 註解:

然後在 spring.factories 中定義如下:

那這種方式是怎麼實現的你,這就要回到我們剛才的方法 getSpringFactoriesInstances :

我們先來看一下傳入參數,這里需要注意的是 args,這個是初始化對應 type 的時候傳入的構造參數,我們先看一下 SpringFactoriesLoader#loadFactoryNames 方法:

首先是會先檢查緩存,假如緩存中存在就直接返回,假如沒有就調用 classLoader#getResources 方法,傳入 META-INF/spring.factories ,即獲取所有 jar 包下的對應文件,並封裝成 UrlResource ,然後使用 PropertiesLoaderUtils 將這些信息讀取成一個對一對的 properties,我們觀察一下 spring.factories 都是按 properties 格式排版的,假如有多個就用逗號隔開,所以這里還需要將逗號的多個類分隔開來,並加到 result 中,由於 result 是一個 LinkedMultiValueMap 類型,支持多個值插入,最後放回緩存中。最終完成載入 META-INF/spring.factories 中的配置,如下:

我們可以看一下我們找到的 initializer 有多少個:

在獲取到所有的 Initializer 後接下來是調用 方法進行初始化。

這里的 names 就是我們上面通過類載入器載入到的類名,到這里會先通過反射生成 class 對象,然後判斷該類是否繼承與 ApplicationContextInitializer ,最後通過發射的方式獲取這個類的構造方法,並調用該構造方法,傳入已經定義好的構造參數,對於 ApplicationContextInitializer 是無參的構造方法,然後初始化實例並返回,回到原來的方法,這里會先對所有的 ApplicationContextInitializer 進行排序,調用 #sort(instances) 方法,這里就是根據 @Order 中的順序進行排序。

接下來是設置 ApplicationListener ,我們跟進去就會發現這里和上面獲取 ApplicationContextInitializer 的方法如出一轍,最終會載入到如圖的 15 個 listener (這里除了 外,其他都是 SpringBoot 內部的 Listener):

在完成 SpringApplication 對象的初始化後,我們進入了他的 run 方法,這個方法幾乎涵蓋了 SpringBoot 生命周期的所有內容,主要分為九個步驟,每一個步驟這里都使用註解進行標識:

主要步驟如下:
第一步:獲取 SpringApplicationRunListener, 然後調用他的 staring 方法啟動監聽器。
第二步:根據 SpringApplicationRunListeners以及參數來准備環境。
第三步:創建 Spring 容器。
第四步:Spring 容器的前置處理。
第五步:刷新 Spring 容器。
第六步: Spring 容器的後置處理器。
第七步:通知所有 listener 結束啟動。
第八步:調用所有 runner 的 run 方法。
第九步:通知所有 listener running 事件。
我們接下來一一講解這些內容。

我們首先看一下第一步,獲取 SpringApplicationRunListener :

這里和上面獲取 initializer 和 listener 的方式基本一致,都是通過 getSpringFactoriesInstances , 最終只找到一個類就是: org.springframework.boot.context.event.EventPublishingRunListener ,然後調用其構造方法並傳入產生 args , 和 SpringApplication 本身:

我們先看一下構造函數,首先將我們獲取到的 ApplicationListener 集合添加到initialMulticaster 中, 最後都是通過操作 來進行廣播,我,他繼承於 ,我們先看一下他的 addApplicationListener 方法:

我們可以看出,最後是放到了 applicationListenters 這個容器中。他是 defaultRetriever 的成員屬性, defaultRetriever 則是 的私有類,我們簡單看一下這個類:

我們只需要看一下這里的 getApplicationListeners 方法,它主要是到 beanFactory 中檢查是否存在多的 ApplicationListener 和舊的 applicationListeners 組合並返回,接著執行 listener 的 start 方法,最後也是調用了 的 multicastEvent 查找支持對應的 ApplicationEvent 類型的通知的 ApplicationListener 的 onApplicationEvent 方法 ,這里除了會:

篩選的方法如下,都是調用了對應類型的 supportsEventType 方法 :

如圖,我們可以看到對 org.springframework.boot.context.event.ApplicationStartingEvent 感興趣的有5個 Listener

環境准備的具體方法如下:

首先是調用 getOrCreateEnvironment 方法來創建 environment ,我們跟進去可以發現這里是根據我們上面設置的環境的類型來進行選擇的,當前環境會創建 StandardServletEnvironment

我們先來看一下 StandardServletEnvironment 的類繼承關系圖,我們可以看出他是繼承了 AbstractEnvironment :

他會調用子類的 customizePropertySources 方法實現,首先是 StandardServletEnvironment 的實現如下,他會添加 servletConfigInitParams , servletContextInitParams , jndiProperties 三種 properties,當前調試環境沒有配置 jndi properties,所以這里不會添加。接著調用父類的 customizePropertySources 方法,即調用到了 StandardEnvironment 。

我們看一下 StandardEnvironment#customizePropertySources 方法,與上面的三個 properties 創建不同,這兩個是會進行賦值的,包括系統環境變數放入 systemEnvironment 中,jvm 先關參數放到 systemProperties 中:

這里會添加 systemEnvironment 和 systemProperties 這兩個 properties,最終拿到的 properties 數量如下 4個:

在創建完成 Environment 後,接下來就到了調用 configureEnvironment 方法:

我們先看一下 configurePropertySources 方法,這里主要分兩部分,首先是查詢當前是否存在 defaultProperties ,假如不為空就會添加到 environment 的 propertySources 中,接著是處理命令行參數,將命令行參數作為一個 CompositePropertySource 或則 添加到 environment 的 propertySources 裡面,

接著調用 ConfigurationPropertySources#attach 方法,他會先去 environment 中查找 configurationProperties , 假如尋找到了,先檢查 configurationProperties 和當前 environment 是否匹配,假如不相等,就先去除,最後添加 configurationProperties 並將其 sources 屬性設置進去。

回到我們的 prepareEnvironment 邏輯,下一步是通知觀察者,發送 事件,調用的是 SpringApplicationRunListeners#environmentPrepared 方法,最終回到了 #multicastEvent 方法,我們通過 debug 找到最後對這個時間感興趣的 Listener 如下:

其主要邏輯如下:

這個方法最後載入了 PropertySourceLoader , 這里主要是兩種,一個是用於 Properties 的,一個是用於 YAML 的如下:

其中 apply 方法主要是載入 defaultProperties ,假如已經存在,就進行替換,而替換的目標 PropertySource 就是 load 這里最後的一個 consumer 函數載入出來的,這里列一下主要做的事情:
1、載入系統中設置的所有的 Profile 。
2、遍歷所有的 Profile ,假如是默認的 Profile , 就將這個 Profile 加到 environment 中。
3、調用load 方法,載入配置,我們深入看一下這個方法:

他會先調用 getSearchLocations 方法,載入所有的需要載入的路徑,最終有如下路徑:

其核心方法是遍歷所有的 propertySourceLoader ,也就是上面載入到兩種 propertySourceLoader ,最紅 loadForFileExtension 方法,載入配置文件,這里就不展開分析了,說一下主要的作用,因為每個 propertySourceLoader 都有自己可以載入的擴展名,默認擴展名有如下四個 properties, xml, yml, yaml,所以最終拿到文件名字,然後通過 - 拼接所有的真實的名字,然後加上路徑一起載入。

接下來,我們分析 BackgroundPreinitializer ,這個方法在接收 ApplicationPrepareEnvironment 事件的時候真正調用了這份方法:

1、 ConversionServiceInitializer 主要負責將包括 日期,貨幣等一些默認的轉換器注冊到 formatterRegistry 中。
2、 ValidationInitializer 創建 validation 的匹配器。
3、 MessageConverterInitializer 主要是添加了一些 http 的 Message Converter。
4、 JacksonInitializer 主要用於生成 xml 轉換器的。
接著回到我們將的主體方法, prepareEnvironment 在調用完成 listeners.environmentPrepared(environment) 方法後,調用 bindToSpringApplication(environment) 方法,將 environment 綁定到 SpirngApplication 中。
接著將 enviroment 轉化為 StandardEnvironment 對象。
最後將 configurationProperties 加入到 enviroment 中, configurationProperties 其實是將 environment 中其他的 PropertySource 重新包裝了一遍,並放到 environment 中,這里主要的作用是方便 進行解析。

它主要是檢查是否存在 spring.beaninfo.ignore 配置,這個配置的主要作用是設置 javaBean 的內省模式,所謂內省就是應用程序在 Runtime 的時候能檢查對象類型的能力,通常也可以稱作運行時類型檢查,區別於反射主要用於修改類屬性,內省主要用戶獲取類屬性。那麼我們什麼時候會使用到內省呢,java主要是通過內省工具 Introspector 來完成內省的工作,內省的結果通過一個 Beaninfo 對象返回,主要包括類的一些相關信息,而在 Spring中,主要是 BeanUtils#Properties 會使用到,Spring 對內省機制還進行了改進,有三種內省模式,如下圖中紅色框框的內容,默認情況下是使用 USE_ALL_BEANINFO。假如設置為true,就是改成第三中 IGNORE_ALL_BEANINFO

首先是檢查 Application的類型,然後獲取對應的 ApplicationContext 類,我們這里是獲取到了 org.springframework.boot.web.servlet.context. 接著調用 BeanUtils.instantiateClass(contextClass); 方法進行對象的初始化。

最終其實是調用了 的默認構造方法。我們看一下這個方法做了什麼事情。這里只是簡單的設置了一個 reader 和一個 scanner,作用於 bean 的掃描工作。

我們再來看一下這個類的繼承關系

這里獲取 ExceptionReporter 的方式主要還是和之前 Listener 的方式一致,通過 getSpringFactoriesInstances 來獲取所有的 SpringBootExceptionReporter 。

其主要方法執行如下:

❿ SpringBoot自動配置的原理及實現/SpringBoot之@Import註解正確使用方式

https://www.jianshu.com/p/6b2f672e2446
了解SpringBoot之@Import註解正確使用方式

SpringBoot 的核心就是自動配置,自動配置又是基於條件判斷來配置 Bean。關於自動配置的源碼在 spring-boot -autoconfigure-2.0.3.RELEASE.jar

在通常需要我們在 property 中配置信息時,通常使用 @ConfigurationProperties(pefix=「前綴」) 註解的方式從配置文件中獲取配置,如下:

application.yml 中配置信息

訪問 url 獲取配置信息返回的值
http://localhost:8080/msg

如果把 application.yml 中的配置信息注釋掉則默認使用 default 值,否則使用配置信息中的值,以上便是普通配置方式

SpringBoot 運行原理
先看 @SpringBootApplication

主要關注的幾個註解如下
@SpringBootConfiguration:標記當前類為配置類
@EnableAutoConfiguration:開啟自動配置
@ComponentScan:掃描主類所在的同級包以及下級包里的 Bean
關鍵是 @EnableAutoConfiguration

最關鍵的要屬 @Import(.class),藉助** **,@EnableAutoConfiguration 可以幫助 SpringBoot 應用將所有符合條件的 @Configuration 配置都載入到當前 SpringBoot 創建並使用的 IoC 容器: 通過 @Import(.class) 導入的配置功能,
中的方法 getCandidateConfigurations,得到待配置的 class 的類名集合, 這個集合就是所有需要進行自動配置的類,而是是否配置的關鍵在於 META-INF/spring.factories 文件中是否存在該配置信息

打開,如下圖可以看到所有需要配置的類全路徑都在文件中,每行一個配置,多個類名逗號分隔, 而 \ 表示忽略換行

整個流程如上圖所示

以 類來看其主要構成部分

都能看到各種各樣的條件判斷註解,滿足條件時就載入這個 Bean 並實例化
此類的條件註解是:@ConditionalOnProperty

@ConditionalOnBean:當容器里有指定 Bean 的條件下
@ConditionalOnClass:當類路徑下有指定的類的條件下
@ConditionalOnExpression:基於 SpEL 表達式為 true 的時候作為判斷條件才去實例化
@ConditionalOnJava:基於 JVM 版本作為判斷條件
@ConditionalOnJndi:在 JNDI 存在的條件下查找指定的位置
@ConditionalOnMissingBean:當容器里沒有指定 Bean 的情況下
@ConditionalOnMissingClass:當容器里沒有指定類的情況下
@ConditionalOnWebApplication:當前項目時 Web 項目的條件下
@:當前項目不是 Web 項目的條件下
@ConditionalOnProperty:指定的屬性是否有指定的值
@ConditionalOnResource:類路徑是否有指定的值
@:當指定 Bean 在容器中只有一個,或者有多個但是指定首選的 Bean
這些註解都組合了 @Conditional 註解,只是使用了不同的條件組合最後為 true 時才會去實例化需要實例化的類,否則忽略
這種 spring4.X 帶來的動態組合很容易後期配置,從而避免了硬編碼,使配置信息更加靈活多變,同時也避免了不必要的意外異常報錯。使用的人只要知道配置的條件即可也不用去閱讀源碼,方便快捷,這也是 sprignboot 快捷方式帶來的好處

參考 HttpEncodingAutoConfiguration 配置信息如下

案例擴展

項目

需要實例化的服務類

配置信息對應的屬性映射類, 需要 pom 中加入 spring-boot-starter 依賴

自動配置文件

在創建如下路徑文件 src/main/resources/META-INF/spring.factories

必須是自動配置類的全路徑

mvn install 該項目

創建一個 springboot-mvc 項目 pom 依賴上面的 jar

http://localhost:8080 / 則返回當前服務的默認值

在 applicaton.yml 中加, 重啟刷新則會更新為如下信息

SpringBoot 自動化配置關鍵組件關系圖
mybatis-spring-boot-starter、spring-boot-starter-web 等組件的 META-INF 文件下均含有 spring.factories 文件,自動配置模塊中,SpringFactoriesLoader 收集到文件中的類全名並返回一個類全名的數組,返回的類全名通過反射被實例化,就形成了具體的工廠實例,工廠實例來生成組件具體需要的 bean。

在 spring boot 中有時候需要控制配置類是否生效, 可以使用 @ConditionalOnProperty 註解來控制 @Configuration 是否生效.

閱讀全文

與springboot解剖源碼相關的資料

熱點內容
游戲開發程序員書籍 瀏覽:841
pdf中圖片修改 瀏覽:268
匯編編譯後 瀏覽:473
php和java整合 瀏覽:828
js中執行php代碼 瀏覽:440
國產單片機廠商 瀏覽:57
蘋果手機怎麼設置不更新app軟體 瀏覽:284
轉行當程序員如何 瀏覽:492
蘋果id怎麼驗證app 瀏覽:864
查看手機命令 瀏覽:953
抖音反編譯地址 瀏覽:225
如何加密軟體oppoa5 瀏覽:233
java從入門到精通明日科技 瀏覽:94
拆解汽車解壓視頻 瀏覽:597
新版百度雲解壓縮 瀏覽:592
android上下拉刷新 瀏覽:880
centos可執行文件反編譯 瀏覽:838
林清玄pdf 瀏覽:271
黑馬程序員java基礎 瀏覽:284
awss3命令 瀏覽:359