springboot介紹、配置文件介紹、自動配置讀取原理
- springBoot學習
- 代碼說明
- 為什么java -jar springJar包后項目就可以啟動
- 配置文件介紹
- 配置文件加載順序
- 其他約定配置文件加載順序
- profile配置文件加載
- 配置文件綁定類屬性
- 通過@Value的方式進行屬性注入
- 通過@ConfigurationProperties的方式進行屬性注入
- 配置文件占位符
- 配置文件-屬性注入:數據校驗
- 通過@PropertySource可以引入外部properties配置文件
- Springboot自動配置底層原理
- springboot配置讀取原理
- 這些注解里面最主要的就是@EnableAutoConfiguration
- @Import({AutoConfigurationImportSelector.class}詳細解讀
- process獲取配置方法解讀
- 自動配置類原理
springBoot學習
依賴引入
<properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.target>8</maven.compiler.target><maven.compiler.source>8</maven.compiler.source></properties><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.6</version></parent><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies><!--打包好幫我們把所有依賴的jar 統統放到jar文件里面的BOOT-INF\lib中設置MANIFEST.MF設置了啟動類 .JarLauncher:自定義類加載器加載所有的jar包,調用start-class。從而啟動項目--><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
代碼說明
所有的springboot都必須繼承spring-boot-starter-parent,通過里面的<artifactId>spring-boot-dependencies</artifactId>幫我們管理了依賴的版本
為什么引入了starter后其他依賴也就被引入了?
一個starter也就是啟動器,內置了很多的依賴,就相當于一個聚合,引入一個starter也就都引入了
為什么java -jar springJar包后項目就可以啟動
- 先打包
將打的jar包解壓可以看到有個BOOT-INF的,里面還有個lib包這個lib包里存的就是項目依賴的其他jar包,叫fat-jar
META-INF中有個MANIFEST.MF文件,里面的Main-Class是所有的jar文件都有的,這個屬性會自定義一個類加載器去加載fat-jar中的jar包。然后調用Start-Class去啟動項目
META-INF中的MANIFEST.MF文件中有一個Main-Class屬性,這個屬性指向了一個自定義的類加載器。這個類加載器在啟動Spring Boot應用時會加載fat-jar中的所有依賴,包括starter依賴。
Start-Class屬性則指定了應用啟動時要執行的類。通過這種方式,Spring Boot能夠在構建的fat-jar中自動尋找并加載所有必要的依賴,從而實現應用的啟動。
配置文件介紹
springboot使用一個全局的配置文件 核心配置文件,配置文件名在 約定的情況下 名字是固定的就叫application
配置文件的作用:修改springboot自動配置的默認值;springboot在底層都給我們自動配置好了。比如端口號,springboot默認端口號8080,但是我們可以通過配置文件覆蓋默認配置。
配置文件加載順序
配置文件讀取優先級:bootstrap.properties>bootstrap.yml>application.properties>application.yml 優先級大的會覆蓋優先級小的
其他約定配置文件加載順序
1、classpath根目錄下
2、classpath根目錄/config
3、項目根目錄
如果當前項目是繼承/耦合 關系maven項目的話,項目根目錄=父maven項目的根目錄。如果是項目只有一個模塊那么項目根目錄 那就是當前模塊的根目錄
4、項目根目錄 /config
如果當前項目是繼承/耦合 關系maven項目的話,項目根目錄=父maven項目的根目錄 /config。如果是項目只有一個模塊那么項目根目錄 那就是當前模塊的根目錄 /config
優先級由上到下,由低到高
profile配置文件加載
多環境配置配置文件
profile文件命名規則:application-名稱.yml
- 在applicaction.yml中進行激活
spring:profiles:active: dev
配置文件綁定類屬性
- 定義實體bean
@Data
@ToString
public class User {private String username;private Integer age;private Date birthday;private List<String> hobbies;private Map<Integer,String> girlFriend;private Address address;
}@Data
public class Address {private Integer id;private String detailAddress;
}
- 定義yml文件
user:username: zzqage: 25
通過@Value的方式進行屬性注入
@Data
@ToString
@Component
public class User {@Value("${user.username}")private String username;@Value("${user.age}")private Integer age;private Date birthday;private List<String> hobbies;private Map<Integer,String> girlFriend;private Address address;
}
- 測試
@SpringBootTest(classes = MyApplication.class)
public class Test {@Autowiredprivate User user;@org.junit.jupiter.api.Testpublic void test(){System.out.println(user);}
}
通過@ConfigurationProperties的方式進行屬性注入
@Data
@ToString
@Component
@ConfigurationProperties(prefix = "user")
public class User {private String username;private Integer age;private Date birthday;private List<String> hobbies;private Map<Integer,String> girlFriend;private Address address;
}
- 測試
@SpringBootTest(classes = MyApplication.class)
public class Test {@Autowiredprivate User user;@org.junit.jupiter.api.Testpublic void test(){System.out.println(user);}
}
@ConfigurationProperties:常用于bean屬性和yml配置文件的綁定。prefix:可以指定配置文件中某一個節點,該節點中的子節點將自動和屬性進行綁定
此外@ConfigurationProperties還支持松散綁定
@value和@ConfigurationProperties區別,最大的一個區別就是@ConfigurationProperties可以匹配多個,@value需要一個一個去匹配,比較麻煩
- 我們目前寫yml文件沒有提示,如果需要提示需要引入spring-boot-configuration-processor依賴
這個依賴會生成METE-INFO 元數據 用于提供idea自動提示配置文件的
<!--這個依賴會生成METE-INFO 元數據 用于提供idea自動提示配置文件的--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><!--依賴不會傳播 如果這是個父模塊,子模塊不會繼承這個依賴--><optional>true</optional></dependency>
- 如果想要自動提示還需要修改idea相關配置
生成的元數據-用于自動提示
- 補充完剩余的屬性
- list類型
hobbies:- 唱歌- 跳舞- 打籃球hobbies: [唱歌、跳舞、打籃球]
- map的類型
girl-friend:18: 范冰冰19: 劉亦菲girl-friend: {18:范冰冰,19:劉亦菲}
- 嵌套對象
address:id: 5detailAddress: 6666
- 完整配置
user:username: zzqage: 123birthday: 2020/01/01hobbies:- 唱歌- 跳舞- 打籃球girl-friend: {18:范冰冰,19:劉亦菲}address:id: 6detailAddress: 6666
配置文件占位符
可以通過${}來引用其他的配置項,這就是配置文件占位符,${}還可以引用springboot內置的一些屬性,比如random.uuid
user:username: zzqage: 123birthday: 2020/01/01hobbies:- 唱歌- 跳舞- 打籃球girl-friend: {18:范冰冰,19:劉亦菲}address:id: 6detailAddress: ${user.username}的家
id: ${random.int}
user:username: zzqage: 123birthday: 2020/01/01hobbies:- 唱歌- 跳舞- 打籃球girl-friend: {18:范冰冰,19:劉亦菲}address:id: ${random.int}detailAddress: ${user.username}的家
配置文件-屬性注入:數據校驗
只支持@ConfigurationProperties,在使用的時候只需要加@Validated(支持對jsr-303數據校驗)
- jsr-303數據校驗
要支持對jsr-303數據校驗還需要加入一個數據校驗的場景啟動器
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>
- 測試 -實體bean要測試的屬性加上注解
@Data
@ToString
@Component
@ConfigurationProperties(prefix = "user")
@Validated
public class User {private String username;private Integer age;private Date birthday;private List<String> hobbies;private Map<Integer,String> girlFriend;@NotNullprivate Address address;
}
- 配置文件配置-去掉address不讓能夠注入
user:username: zzqage: 123birthday: 2020/01/01hobbies:- 唱歌- 跳舞- 打籃球girl-friend: {18:范冰冰,19:劉亦菲}
結果
通過@PropertySource可以引入外部properties配置文件
- properties配置
user.username=zzq
user.age=123
user.birthday=2020/02/06
user.hobbies=[跳舞、唱歌]
user.girlFriend.18=范冰冰
user.girlFriend.19=劉亦菲
user.address.id=5
user.address.detailAddress=上海
- 實體bean配置-@PropertySource(“classpath:data/user.properties”)
@Data
@ToString
@Component
@ConfigurationProperties(prefix = "user")
@Validated
@PropertySource("classpath:data/user.properties")
public class User {private String username;private Integer age;private Date birthday;private List<String> hobbies;private Map<Integer,String> girlFriend;private Address address;
}
Springboot自動配置底層原理
springboot配置讀取原理
@SpringBootConfiguration:Spring Boot的配置類:標注在某個類上,表示這是一個Spring Boot的配置類
@Configuration:配置類上來標注這個注解,配置類也是容器的一個組件
@EnableAutoConfiguration:開啟自動配置功能:以前我們需要配置的東西,Spring Boot幫我們自動配置;@EnableAutoConfiguration告訴SpringBoot開啟自動配置功能,會幫我們自動去加載配置類,這樣自動配置才能生效
@ComponentScan:掃描包,如果沒有指定掃描包spring底層會自動掃描當前配置類所在的包和子包, TypeExcludeFilter:springboot對外提供的擴展類,可以供我們去按照我們的自定義的方式進行排除。AutoConfigurationExcludeFilter:排除所有實現了AutoConfigurationExcludeFilter 接口 配置類并且自動配置類
這些注解里面最主要的就是@EnableAutoConfiguration
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";Class<?>[] exclude() default {};String[] excludeName() default {};
}
- @AutoConfigurationPackage
這個注解的作用:將當前配置類所在包保存在BasePackages的Bean中。供Sspring內部使用
@Import({AutoConfigurationPackages.Registrar.class}) //保存掃描路徑,提供給spring-data-jpa
public @interface AutoConfigurationPackage {
就是注冊了一個保存當前配置類所在包的一個bean
@Import({AutoConfigurationImportSelector.class}詳細解讀
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
AutoConfigurationImportSelector是一個實現了DeferredImportSelector的selector類
- 復習ImportSelector
作用:返回類路徑的完整限定名,并且將這些類注冊成bean
- DeferredImportSelector:變種的延遲ImportSelector
DeferredImportSelector工作原理
- 具體使用
如果getImportGroup為空則執行importselectors,否則執行getImportGroup返回類的selectImports
public class MyImportSelector implements DeferredImportSelector {@Overridepublic Class<? extends Group> getImportGroup() {return AutoConfigurationGroupdd.class;}@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {return new String[]{"com.springboot.controller.bean.User"};}private static class AutoConfigurationGroupdd implements DeferredImportSelector.Group{AnnotationMetadata metadata;@Overridepublic void process(AnnotationMetadata metadata, DeferredImportSelector selector) {}@Overridepublic Iterable<Entry> selectImports() {List<Entry> list =new ArrayList<>();list.add(new Entry(this.metadata,"com.springboot.controller.bean.Person"));return list;}}
}
process獲取配置方法解讀
process方法可以獲取META-INF/spring.factories里面的內容并把內容給selectorimports方法讓這個方法去把spring.factories里面的配置注冊成bean
//獲取spring.factories里面的配置類@Overridepublic void process(AnnotationMetadata metadata, DeferredImportSelector selector) {}//將配置類注冊成bean@Overridepublic Iterable<Entry> selectImports() {}
getAutoConfigurationEntry—>getCandidateConfigurations
getCandidateConfigurations再通過spring加載器來獲取配置
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
自動配置類原理
以HttpEncodingAutoConfiguration為例
@Configuration(proxyBeanMethods = false
)
@EnableConfigurationProperties({ServerProperties.class})
@ConditionalOnWebApplication(type = Type.SERVLET
)
@ConditionalOnClass({CharacterEncodingFilter.class})
@ConditionalOnProperty(prefix = "server.servlet.encoding",value = {"enabled"},matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {private final Encoding properties;public HttpEncodingAutoConfiguration(ServerProperties properties) {this.properties = properties.getServlet().getEncoding();}@Bean@ConditionalOnMissingBeanpublic CharacterEncodingFilter characterEncodingFilter() {CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();filter.setEncoding(this.properties.getCharset().name());filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.REQUEST));filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.RESPONSE));return filter;}
}
- @Configuration( proxyBeanMethods = false)詳解
標記了@Configuration Spring底層會給配置創建cglib動態代理,目的:給標記了@bean的方法在創建bean的時候,會執行動態代理類(這個動態代理類會先從ioc容器里面拿如果拿不到在調用bean方法進行創建,以滿足單例模式)
所以 proxyBeanMethods = false,就不讓它去產生代理類 - @EnableConfigurationProperties({ServerProperties.class})詳解
啟用可以在配置類設置的屬性 對應的類(在配置文件中可以寫哪些屬性就由這個配置類中的屬性決定)
啟用配置類的屬性:里面導入了一個屬性配置類