原理初探
pom.xml
- spring-boot-dependencies:核心依賴在父工程中
- 我們在寫或者引入一些Springboot依賴的時候,不需要指定版本,就因為有這些版本倉庫
啟動器
-
通式
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-xxx</artifactId> </dependency>
-
啟動器:說白了就是springboot的啟動場景
-
比如,spring-boot-starter-web,他就會幫我們自動導入web環境所有的依賴
-
springboot會將所有的功能場景,都變成一個個的啟動器
-
我們要使用什么功能,就只需要找到對應的啟動器就可以了
starter
主程序
@SpringBootApplication //標注這個類是一個springboot的應用
public class HelloworldApplication {
public static void main(String[] args) {
//將springboot應用啟動
SpringApplication.run(HelloworldApplication.class, args);
}
}
- 注解
@SpringBootConfiguration:springboot的配置
@Configuration:spring配置類
@Component:說明這也是一個spring的組件
@EnableAutoConfiguration:自動配置
@AutoConfigurationPackage:自動配置包
@Import({Registrar.class}):導入選擇器,包注冊
@Import({AutoConfigurationImportSelector.class}):自動配置導入選擇
List configurations = this.getCandidateConfigurations(annotationMetadata, attributes); //獲取所有的配置
獲取候選的配置
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:自動配置的核心文件
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
//所有資源加載到配置類中!
結論:springboot所有自動配置都是在啟動的時候掃描並加載:spring.factories
所有的自動配置類都在這里面,但是不一定生效,要判斷條件是否成立,只要導入了對應的start,就有對應的啟動器了,有了啟動器,我們自動裝配就會生效,然后就配置成功!
- springboot在啟動的時候,從類路徑下 /MEAT-INF/
spring.factories
獲取指定的值 - 將這些自動配置的類導入容器,自動配置就會生效,幫我進行自動配置
- 以前我們需要自動配置的東西,現在 springboot 幫我們做了
- 整個javaEE,解決方案和自動配置的東西都在 spring-boot-autoconfigure-2.2.0.RELEASE.jar 這個包下
- 它會把所有需要導入的組件,以類名的方式返回,這些組件就會被添加到容器
- 容器中也會存在非常多的 xxxAutoConfiguration 的文件(@Bean),就是這些類給容器中導入了這個場景需要的所有組件;並自動配置,@Configuration,JavaConfig!
- 有了自動配置類,免去了我們手動編寫配置注入功能組件等的工作
SpringApplication這個類(加了@SpringApplication注解的主類)主要做了以下四件事情:
- 推斷應用的類型是普通的項目還是Web項目
- 查找並加載所有可用初始化器, 設置到 initializers 屬性中
- 找出所有的應用程序監聽器,設置到 listeners 屬性中
- 推斷並設置main方法的定義類,找到運行的主類
springboot配置
配置文件
SpringBoot使用一個全局的配置文件,配置文件名稱是固定的
- application.properties
語法結構:key=value
- application.yaml
。語法結構:key: 空格value
配置文件的作用:修改SpringBoot自動配置的默認值,因為SpringBoot在底層都給我們自動配置好了
#springboot配置文件都能配置什么東西呢?
#官方文檔:https://docs.spring.io/spring-boot/docs/2.1.6.RELEASE/reference/htmlsingle/#boot-features-external-config
#Part X. Appendices Appendix A. Common application properties
#官方的配置太多了,了解原理
##基本語法,對空格縮進要求很高
#普通的key-value
name: peng
#存一個對象
student:
name: peng
age: 18
#行內寫法
student: {name: peng,age: 18}
#數組
pets:
- cat
- dog
pet: [cat,dog,pig]
yaml 可以直接給實體類賦值
yaml配置類的屬性
application.yaml 配置
person:
name: peng${random.uuid}
age: 18
happy: false
birth: 2001/06/03
maps: {k1: v1,k2: v2}
lists: [eat,sleep,girl]
dog:
name: ${person.name:沒有主人}的狗 #冒號后面的是默認值
age: ${random.int(1,5)}
Person.java Person類
package com.peng.pojo;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Component
@ConfigurationProperties(prefix = "person") //綁定yanl,讓yaml生效
public class Person {
private String name;
private Integer age;
private boolean happy;
private Date birth;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
public Person() {
}
public Person(String name, Integer age, boolean happy, Date birth, Map<String, Object> maps, List<Object> lists, Dog dog) {
this.name = name;
this.age = age;
this.happy = happy;
this.birth = birth;
this.maps = maps;
this.lists = lists;
this.dog = dog;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public boolean isHappy() {
return happy;
}
public void setHappy(boolean happy) {
this.happy = happy;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public Map<String, Object> getMaps() {
return maps;
}
public void setMaps(Map<String, Object> maps) {
this.maps = maps;
}
public List<Object> getLists() {
return lists;
}
public void setLists(List<Object> lists) {
this.lists = lists;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", happy=" + happy +
", birth=" + birth +
", maps=" + maps +
", lists=" + lists +
", dog=" + dog +
'}';
}
}
Spring02ConfigApplicationTest.java 測試類
package com.peng;
import com.peng.pojo.Person;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class Spring02ConfigApplicationTest {
@Autowired
private Person person;
@Test
public void contextLoads() {
System.out.println(person);
}
}
輸出:
Person{name='peng24756efe-3e05-4d61-abe7-f31e59e94f6f', age=18, happy=false, birth=Sun Jun 03 00:00:00 CST 2001, maps={k1=v1, k2=v2}, lists=[eat, sleep, girl], dog=Dog{name='peng92a5f5f2-3149-4336-9c45-76da5e680285的狗', age=3}}
-
松散綁定
lastName,在yaml中可以寫成last-name
-
JSR303校驗:賦值前驗證數據類型
@Validated //數據校驗 public class Person { @NotNull //傳入的值必須不為空才能通過驗證 private String name; }
Bean Validation 中內置的 constraint
Hibernate Validator 附加的 constraint
多環境配置
#springboot的多環境配置:可以選擇激活哪一個配置文件
server:
port: 8080
spring:
profiles:
active: dev
# --- 分文檔模塊
---
server:
port: 8081
spring:
profiles: dev
---
server:
port: 8082
spring:
profiles: test
淺顯的底層原理
# 配置文件里到底能寫什么 --聯系-- spring.factories
# 在我們這配置文件中能配置的東西,都存在一個固有的規律
# xxxAutoConfiguration --連接-- xxxProperties --連接-- yaml
# xxxAutoConfiguration:自動裝配的默認值
# xxxProperties有set方法改變默認值,和配置文件yaml綁定,設置新值並使用
server:
port: 8080
ctrl+鼠標左鍵,點進 port 看源碼,果然有 port 屬性和 set 方法
private Integer port;
public void setPort(Integer port) {
this.port = port;
}
發現這個方法屬於 ServerProperties 類,類上有注解 @ConfigurationProperties,他連接 server 的默認配置文件
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties{...}
自動默認配置文件中果然有
點進去之后,確實是個自動配置類,在注解中,他允許了 ServerProperties 類重新設置 port 等屬性,這些設置可通過配置文件 yaml 配置
而 ServerProperties 類連接 yaml,就是通過之前說過的 @ConfigurationProperties 注解,點進 prefix,是一個配置屬性的注解
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
本質:我們原先需要在 bean 中配置的屬性(properties)封裝成一個類然后通過 yaml 文件進行自動注入,而我們可以在 application.yaml 文件中自定義這些 property 屬性
-
自動裝配原理總結
-
SpringBoot 啟動會加載大量的自動配置類
-
我們看我們需要的功能有沒有在SpringBoot默認寫好的自動配置類當中
-
我們再來看這個自動配置類中到底配置了哪些組件;(只要我們要用的組件存在在其中,我們就不需要再手動配置了)
-
給容器中自動配置類添加組件的時候,會從properties類中獲取某些屬性。我們只需要在配置文件中指定這些屬性的值即可
xxxAutoConfigurartion:自動配置類;給容器中添加組件
xxxProperties:封裝配置文件中相關屬性;
-
-
通過 debug=true 來查看,哪些配置生效,哪些沒有
debug: true