1.配置優先級
3種配置文件:
- application.properties
server.port=8081
- application.yml
server:port: 8082
- application.yaml
server:port: 8082
2種外部屬性的配置(Java系統屬性、命令行參數):
- Java系統屬性配置 (格式: -Dkey=value)
-Dserver.port=9000
- 命令行參數 (格式:–key=value)
--server.port=10010
優先級(從低到高):
- application.yaml(忽略)
- application.yml
- application.properties
- java系統屬性(-Dxxx=xxx)
- 命令行參數(–xxx=xxx)
2.Bean的管理
2.1 Bean的作用域
- 可以借助Spring中的
@Scope
注解來進行配置作用域
注意事項:
- IOC容器中的bean默認使用的作用域:
singleton (單例)
- 默認singleton的bean,在容器啟動時被創建,可以使用
@Lazy
注解來延遲初始化(延遲到第一次使用時)prototype
的bean,每一次使用該bean的時候都會創建一個新的實例- 實際開發當中,絕大部分的Bean是單例的,也就是說絕大部分Bean不需要配置scope屬性
2.2第三方Bean
之前我們所配置的bean,像controller、service,dao三層體系下編寫的類,這些類都是我們在項目當中自己定義的類(自定義類)。當我們要聲明這些bean,也非常簡單,我們只需要在類上加上@Component以及它的這三個衍生注解(@Controller、@Service、@Repository),就可以來聲明這個bean對象了。
但是在我們項目開發當中,還有一種情況就是這個類它不是我們自己編寫的,而是我們引入的第三方依賴當中提供的,那么此時我們是無法使用 @Component 及其衍生注解來聲明bean的,此時就需要使用@Bean
注解來聲明bean 了。
演示1:
- 在啟動類中直接聲明這個Bean。比如:我們可以將我們之前使用的阿里云OSS操作的工具類,基于@Bean注解的方式來聲明Bean。
import com.itheima.utils.AliyunOSSOperator;
import com.itheima.utils.AliyunOSSProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableScheduling;@ServletComponentScan
@EnableScheduling
@SpringBootApplication
public class TliasWebManagementApplication {public static void main(String[] args) {SpringApplication.run(TliasWebManagementApplication.class, args);}@Beanpublic AliyunOSSOperator aliyunOSSOperator(AliyunOSSProperties ossProperties) {return new AliyunOSSOperator(ossProperties);}
}
演示2:
若要管理的第三方 bean 對象,建議對這些bean進行集中分類配置,可以通過 @Configuration
注解聲明一個配置類。【推薦】
package com.itheima.config;import com.itheima.utils.AliyunOSSOperator;
import com.itheima.utils.AliyunOSSProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class OSSConfig {@Beanpublic AliyunOSSOperator aliyunOSSOperator(AliyunOSSProperties ossProperties) {return new AliyunOSSOperator(ossProperties);}
}
- 通過
@Bean
注解的name 或 value屬性可以聲明bean的名稱,如果不指定,默認bean的名稱就是方法名。- 如果第三方bean需要依賴其他bean對象,直接在bean定義方法中設置形參即可,容器會根據類型自動裝配。
3.SpringBoot原理
3.1起步依賴
當我們引入了 spring-boot-starter-web 之后,maven會通過依賴傳遞
特性,將web開發所需的常見依賴都傳遞下來。
3.2自動配置
SpringBoot的自動配置就是當spring容器啟動后,一些配置類、bean對象就自動存入到了IOC容器中,不需要我們手動去聲明,從而簡化了開發,省去了繁瑣的配置操作。
3.2.1實現方案
3.2.1.1方案一
@ComponentScan
組件掃描
@SpringBootApplication
@ComponentScan({"com.itheima","com.example"}) //指定要掃描的包
public class SpringbootWebConfigApplication {public static void main(String[] args) {SpringApplication.run(SpringbootWebConfigApplication.class, args);}
}
3.2.1.2方案二
@Import導入
- 導入形式主要有以下幾種:
- 導入普通類
- 導入配置類
- 導入ImportSelector接口實現類
1). 使用@Import
導入普通類:
@Import(TokenParser.class) //導入的類會被Spring加載到IOC容器中
@SpringBootApplication
public class SpringbootWebConfigApplication {public static void main(String[] args) {SpringApplication.run(SpringbootWebConfigApplication.class, args);}
}
2). 使用@Import導入配置類
- 配置類
@Configuration
public class HeaderConfig {@Beanpublic HeaderParser headerParser(){return new HeaderParser();}@Beanpublic HeaderGenerator headerGenerator(){return new HeaderGenerator();}
}
- 啟動類
@Import(HeaderConfig.class) //導入配置類
@SpringBootApplication
public class SpringbootWebConfig2Application {public static void main(String[] args) {SpringApplication.run(SpringbootWebConfig2Application.class, args);}
}
3). 使用@Import導入ImportSelector接口實現類:
- ImportSelector接口實現類
public class MyImportSelector implements ImportSelector {public String[] selectImports(AnnotationMetadata importingClassMetadata) {//返回值字符串數組(數組中封裝了全限定名稱的類)return new String[]{"com.example.HeaderConfig"};}
}
- 啟動類
@Import(MyImportSelector.class) //導入ImportSelector接口實現類
@SpringBootApplication
public class SpringbootWebConfig2Application {public static void main(String[] args) {SpringApplication.run(SpringbootWebConfig2Application.class, args);}
}
4). 使用第三方依賴提供的 @EnableXxxxx
注解(best)
- 第三方依賴中提供的注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyImportSelector.class)//指定要導入哪些bean對象或配置類
public @interface EnableHeaderConfig {
}
- 在使用時只需在啟動類上加上
@EnableXxxxx
注解即可
@EnableHeaderConfig //使用第三方依賴提供的Enable開頭的注解
@SpringBootApplication
public class SpringbootWebConfig2Application {public static void main(String[] args) {SpringApplication.run(SpringbootWebConfig2Application.class, args);}
}
3.2.2原理分析
3.2.2.1源碼跟蹤
源碼跟蹤技巧:
在跟蹤框架源碼的時候,一定要抓住關鍵點,找到核心流程。一定不要從頭到尾一行代碼去看,一個方法的去研究,一定要找到關鍵流程,抓住關鍵點,先在宏觀上對整個流程或者整個原理有一個認識,有精力再去研究其中的細節。
在@SpringBootApplication注解中包含了:
- 元注解(不再解釋)
- @SpringBootConfiguration
- @EnableAutoConfiguration
- @ComponentScan
自動配置源碼小結:
自動配置原理源碼入口就是 @SpringBootApplication 注解,在這個注解中封裝了3個注解,分別是:
- @SpringBootConfiguration
- 聲明當前類是一個配置類
- @ComponentScan
- 進行組件掃描(SpringBoot中默認掃描的是啟動類所在的當前包及其子包)
- @EnableAutoConfiguration
- 封裝了@Import注解(Import注解中指定了一個ImportSelector接口的實現類)
在實現類重寫的selectImports()方法,讀取當前項目下所有依賴jar包中META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
兩個文件里面定義的配置類(配置類中定義了@Bean注解標識的方法)。
- 封裝了@Import注解(Import注解中指定了一個ImportSelector接口的實現類)
當SpringBoot程序啟動時,就會加載配置文件當中所定義的配置類,并將這些配置類信息(類的全限定名)封裝到String類型的數組中,最終通過@Import注解將這些配置類全部加載到Spring的IOC容器中,交給IOC容器管理。
3.2.2.2 @Conditional
@Conditional注解:
- 作用:按照一定的條件進行判斷,在滿足給定條件后才會注冊對應的bean對象到Spring的IOC容器中。
- 位置:
方法、類
- @Conditional本身是一個父注解,派生出大量的子注解:
@ConditionalOnClass
:判斷環境中有對應字節碼文件,才注冊bean到IOC容器。@ConditionalOnMissingBean
:判斷環境中沒有對應的bean(類型或名稱),才注冊bean到IOC容器。@ConditionalOnProperty
:判斷配置文件中有對應屬性和值,才注冊bean到IOC容器。
最后再給大家梳理一下自動配置原理:
自動配置的核心就在@SpringBootApplication注解上,SpringBootApplication這個注解底層包含了3個注解,分別是:
- @SpringBootConfiguration
- @ComponentScan
- @EnableAutoConfiguration
@EnableAutoConfiguration這個注解才是自動配置的核心。
- 它封裝了一個@Import注解,Import注解里面指定了一個ImportSelector接口的實現類。
- 在這個實現類中,重寫了ImportSelector接口中的selectImports()方法。
- 而selectImports()方法中會去讀取兩份配置文件,并將配置文件中定義的配置類做為selectImports()方法的返回值返回,返回值代表的就是需要將哪些類交給Spring的IOC容器進行管理。
- 那么所有自動配置類的中聲明的bean都會加載到Spring的IOC容器中嗎? 其實并不會,因為這些配置類中在聲明bean時,通常都會添加@Conditional開頭的注解,這個注解就是進行條件裝配。而Spring會根據Conditional注解有選擇性的進行bean的創建。
- @Enable 開頭的注解底層,它就封裝了一個注解 import 注解,它里面指定了一個類,是 ImportSelector 接口的實現類。在實現類當中,我們需要去實現 ImportSelector 接口當中的一個方法 selectImports
這個方法。這個方法的返回值代表的就是我需要將哪些類交給 spring 的 IOC容器進行管理。- 此時它會去讀取兩份配置文件,一份兒是 spring.factories,另外一份兒是 autoConfiguration.imports。而在 autoConfiguration.imports
這份兒文件當中,它就會去配置大量的自動配置的類。- 而前面我們也提到過這些所有的自動配置類當中,所有的 bean都會加載到 spring 的 IOC 容器當中嗎?其實并不會,因為這些配置類當中,在聲明 bean 的時候,通常會加上這么一類@Conditional
開頭的注解。這個注解就是進行條件裝配。所以SpringBoot非常的智能,它會根據 @Conditional
注解來進行條件裝配。只有條件成立,它才會聲明這個bean,才會將這個 bean 交給 IOC 容器管理。
3.2.3自定義starter
3.2.3.1實現
- 第1步:創建自定義starter模塊
aliyun-oss-spring-boot-starter
(進行依賴管理)- 把阿里云OSS所有的依賴統一管理起來
- 第2步:創建autoconfigure模塊
aliyun-oss-spring-boot-autoconfigure
- 在starter中引入autoconfigure (我們使用時只需要引入starter起步依賴即可)
- 第3步:在autoconfigure模塊
aliyun-oss-spring-boot-autoconfigure
中完成自動配置- 定義一個自動配置類,在自動配置類中將所要配置的bean都提前配置好
- 定義配置文件,把自動配置類的全類名定義在配置文件(
META-INF/spring/xxxx.imports
)中