主頁 > 後端開發 > SpringBoot核心技術

SpringBoot核心技術

2021-03-05 11:07:42 後端開發

基礎篇 SpringBoot基礎入門

1.1 SpringBoot入門

1.1.1 系統要求

  • Java8+
  • Maven3.3+
  • idea2019.2+

1.1.2 maven設定

  1. 配置為阿里云的倉庫
  2. 設定jdk版本為1.8

1.1.3 SpringBoot常見注解

@RequestMapping:映射請求,
@ResponseBody:表明回傳的是字串,而不是跳轉頁面,
@RestController:輕量級的標注,為@ResponseBody和@RequestMapping的合體,

1.1.4 創建SpringBoot專案

  • 創建maven專案
  • 匯入父工程
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.3</version>
    </parent>
  • 添加場景依賴
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
  • 寫主程式,在主程式上標注 @SpringBootApplication,表示這是一個SpringBoot應用,在主程式中運用run()把應用跑起來
	@SpringBootApplication
    public static void main(String[] args) {
        SpringApplication.run(Example.class, args);
    }
  • 撰寫業務
  • 測驗
  • 簡化配置,所有的配置內容,都可以在application.properties中配置,
server.port=8080
  • 簡化部署【添加插件】,把專案打成jar包,直接在目標服務器運行,
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

1.2 了解自動配置

1.2.1 依賴管理

  • 父專案做依賴管理
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.3</version>
    </parent>
  • 開發匯入starter場景啟動器
1.spring-boot-starter-*表示各種型別的場景,
2.只要引入starter,這個場景的各種依賴我們都能自動引入,
3.SpringBoot支持的各種場景:https://docs.spring.io/spring-boot/docs/2.4.3/reference/html/using-spring-boot.html#using-boot-starter
4.見到的*-spring-boot-starter-*為第三方的場景,
  • 無需關注版本,自動仲裁版本【引入依賴基本不用寫版本號,但引入非版本仲裁的要寫版本號】,
  • 可以自定義依賴版本號,在pom.xml中修改< properties><\properties>,

1.2.2 自動配置

  • 自動配好Tomcat,
1.引入Tomcat組件
2.自動配好Tomcat依賴
  • 自動配好SpringMVC,
1.引入SpringMVC全套組件
2.自動配好SpringMVC常用組件
  • 自動配好Web常見功能,如:字符編碼問題,
  • 默認的包結構,
1.主程式下所在包下及其下的所有子包里面的組件都會被默認掃描,以前的包掃描不用配置,
2.若想掃描主程式之上的包則需要如下配置:@SpringBootApplication(scanBasePackages="xxx.xxx")或通過@Component("xxx.xxx"),
  • 各種配置擁有默認值
  • 按需加載各種配置項
非常多的starter
引入哪個場景這個場景的自動配置才會開啟
SpringBoot的所有自動配置功能都在spring-boot-autoConfigure包里

1.2.3 組件添加

@Configuration

  • 用@Configuration標注的配置類本身也是組件,
  • 配置類里面使用@Bean標注在方法上給容器注冊組件,默認也是單實體,
  • full模式:@Configuration(proxyBeanMethods=true),
  • lite模式:@Configuration(proxyBeanMethods=false),
  • 最佳實戰:
 - 配置類組件之間沒有依賴關系,使用lite模式,加快容器啟動程序,減少判斷,
 - 配置類組件之間有依賴關系,會使用到之前的單實體組件,使用full模式,但容器啟動會變慢,

@Import({User.class,DBHelper.class}):給容器中創建出這兩個型別的組件,默認組件就是全類名,
@ImportResource:匯入資源檔案

1.2.4 配置系結

把組態檔中的值系結在容器中,

  1. @Component+@ConfigurationProperties【只有在容器中,才能使用SpringBoot的功能】
@Component
@ConfigurationProperties(preifx="myCar")
public class Car{
}
  1. @EnableConfigurationProperties+ @ConfigurationProperties【在配置類中加入@EnableConfigurationProperties,來開啟配置系結功能,并把組件自動注冊到容器中】

1.2.5 自動配置入門

  1. 引導加載自動配置類
//注解@SpringBootApplication拆分
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)

@SpringBootConfiguration:代表當前是一個配置類,
@ComponentScan:開啟包掃描,
@EnableAutoConfiguration

//@EnableAutoConfiguration的注解
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {}

@AutoConfigurationPackage

@Import({Registrar.class})//給容器中匯入一個組件
public @interface AutoConfigurationPackage {}

//利用Registrar給容器匯入一系列組件
//將主程式所在的包下的所有組件都導進來
  1. 按需開啟自動配置項:雖然127個場景的所有自動配置啟動時默認全部加載,但是要按照條件裝配原則,最侄訓按需加載【@Conditional】,
\META-INF\spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
......
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration

  1. 修改默認配置,SpringBoot會在底層配置好所有組件,但是如果用戶自己配置了,以用戶配置的優先,

總結:

  • SpringBoot先加載所有的自動配置類:xxxxAutoConfiguration,
  • 每個自動配置類按照條件自動生效,默認都會系結組態檔指定的值,xxxProperties里面拿,xxxProperties和組態檔進行了系結,
  • 生效的配置類會在容器中裝配很多組件,
  • 只要容器中這些組件有了,就相當于這些功能有了,
  • 定制化配置:用戶自己用@Bean替換底層的組件,用戶去看這個組件系結了組態檔中的什么值就去修改,xxxxAutoConfiguration---->組件---->xxxxProperties里面拿值---->application.properties

1.2.6 最佳實踐

  • 引入場景依賴
  • 查看有哪些自動配置了【選做】
1.自己分析,引入場景對應的自動配置一般都生效了
2.組態檔中debug=true開啟自動配置報告,Negative(不生效)\Positive(生效)
  • 是否需要修改
參照檔案修改配置項
自定義加入或替換組件
自定義器xxxxCustomizer

1.2.7 開發小技巧

1.2.7.1 Lombok

簡化Java Bean的開發,

  1. 引入依賴
	<dependency>
    	<groupId>org.projectlombok</groupId>
    	<artifactId>lombok</artifactId>
	</dependency>
  1. 安裝插件【在idea中安裝】
  2. 相關注解,
    @Data:注解在類上, 為類提供讀寫屬性, 此外還提供了 equals()、hashCode()、toString() 方法,
    @ToString:重寫tostring(),
    @NoArgsConstructor:無參構造器,
    @AllArgsConstructor:全參構造器,
    @EqualsAndHashCode:重寫equals()和hashCode(),
    @Slf4j:開啟日志功能,
1.2.7.2 dev-tools

Ctrl+F9:重新編譯,自動重啟,利于修改靜態頁面,

	//引入依賴,
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
    </dependency>
1.2.7.3 Spring Initailizr

專案初始化向導,幫助開發SpringBoot專案,

  1. 創建專案時選擇開發所需要的場景,
  2. 自動創建主程式類,
  3. 自動匯入專案所需的依賴,
  4. 自動創建場景開發所需的檔案夾,
    自動創建場景開發所需的檔案夾

核心篇 SpringBoot核心技術

2.1 組態檔

常規的是properties檔案,也可以使用yaml,yaml非常適合以資料為中心的組態檔,是輕量級的,但按照優先級,SpringBoot會最終加載properties中的配置,

2.1.1 基本語法

  1. 使用key: value來儲存,kv之間有空格,
  2. 使用縮進來表示層級關系,
  3. 只可以使用空格來表示縮進,不可以使用tab,【但idea等設定了用空格代替縮進的IDE可以隨意使用空格或者tab】
  4. 縮進的空格數可以不同,只要相同的層級的元素左對齊就可以,
  5. '#'代表注釋,
  6. 大小寫敏感,
  7. 字串無需加引號,如果要加,’'與""表示字串內容,會被轉義/不轉義,

2.1.2 資料型別

  1. 字面量:單個不可再分的,data,Boolean,string,number,null,
k: v
  1. 物件:map,hash,set,object,
行內寫法:   k: {k1: v1,k2: v2,k3: v3}
#或
k:
	k1: v1
	k2: v2
	k3: v3
  1. 陣列:array,list,queue,
行內寫法:   k: [v1,v2,v3]
#或
k:
	- v1
	- v2
	- v3

2.1.3 配置提示

pom.xml在添加:

<dependencys>
	<dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-configuration-processor</artifactId>
	    <optional>true</optional>
	</dependency>
</dependencys>

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <proc>none</proc>
    </configuration>
</plugin>

2.2 Web開發

2.2.1 簡單功能分析

2.2.1.1 靜態資源訪問

靜態資源目錄:只要靜態資源放在類路徑下的/static、/public、/resources、/META-INF/resources,訪問當前專案根路徑/+靜態資源名,

原理:靜態資源/**,請求進來,先去找Controller看能不能處理,不能處理的請求又交給靜態資源處理器,靜態資源找不到就404,

靜態資源訪問前綴:默認無前綴,可在組態檔中修改,當前專案+static-path-pattern+靜態資源名=靜態資源檔案夾下找,

webjar:支持webjar,

2.2.1.2 歡迎頁訪問
  • 靜態路徑下的index.html
  • controller能處理/index
2.2.1.3 自定義Favicon

將favicon.ico圖示放在靜態資源路徑下即可以訪問,

2.2.1.4 靜態資源配置原理
  • 專案啟動,SpringBoot加載xxxAutoConfiguration(自動配置類),
  • SpringMVC的自動配置類大多在webMvcAutoConfiguration,
@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {}
  • 給容器中配了什么,
    @Configuration(
        proxyBeanMethods = false
    )
    @Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
    @EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class})
    @Order(0)
    public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {}
  • 組態檔的相關屬性和xxx進行了系結,WebMvcProperties跟spring.mvc進行了系結,ResourceProperties跟spring.resources進行了系結,

2.2.2 SpringMVC在底層可以處理的web請求

  • 注解:@RequestParam
  • Servlet API:HTTPSession
  • 復雜引數:Map、Model
  • 自定義物件引數:Person

@GetMapping:用于處理請求方法的GET型別,

@PathVariable:獲取路徑變數上的引數,可以單個獲取,也可以用Map<String,String>的方式集體獲取,

@RequestHeader:獲取請求頭資訊,可以單個獲取,也可以用Map<String,String>的方式集體獲取,

@RequestParam:獲取請求引數,可以單個獲取,也可以用Map<String,String>的方式集體獲取,

@CookieValue:獲取Cookie中的值,可以單個獲取,也可以用Cookie的方式整體獲取,

@RequestBody:獲取請求體【POST請求才有請求體】,

@RequestAttribute:獲取請求域屬性的值,

@MatrixVariable:獲取矩陣變數的值,但是SpringBoot默認禁用了矩陣變數的功能,需要手動開啟,原理:對于路徑處理,都是用UrlPathHelper決議的,UrlPathHelper中的removeSemicolonContent屬性是用來設定是否禁用分號內容【矩陣變數必須有路徑變數才可以被決議】,

/cars/{path}?xxx=xxx?xxx=xxx queryString 查詢字串,使用@RequestParam的方式獲取請求引數,
/cars/{path};xxx=xxx;yyy=aaa,bbb,ccc 矩陣變數,使用@MatrixVariable的方式獲取引數,

面試題:當Cookie禁用了,session中的值怎么使用?
【session.set(a,b)--->jsessionid--->cookie--->每次發請求攜帶】
通過URL重寫:/abc;jsessionid=xxx 把cookie的值用矩陣變數進行傳遞,

2.2.3 視圖決議

thymeleaf使用

  1. 引入依賴
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf</artifactId>
    <version>3.0.12.RELEASE</version>
</dependency>
  1. 自動配置好了thymeleaf

2.3 資料訪問

2.3.1 資料源的自動配置

  1. 匯入jdbc場景
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>

自動配置的項:
引入的依賴因為官方不知道我們需要操作什么資料庫,所有缺少資料庫驅動,需要手動匯入,

<!--注意springboot的版本仲裁,需要查看本機中資料庫的版本號來修改版本,可以在<dependency>中加修改</version>,也可以在prom.xml檔案中修改version,-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
  1. 分析自動配置類,
  2. 修改配置項,在組態檔中配置資料庫連接地址、用戶名、密碼、資料庫驅動【spring.datasource】,配置資料庫相關的屬性【spring.jdbc】,

2.3.2 使用druid資料源

  1. 引入druid-starter,
  2. 分析自動配置,
    1.擴展配置項spring.datasource.durid,
    2.DruidSpringAopConfiguration.class:監控SpringBean的,配置項:spring.datasource.durid.aop-pattern,
    3.DruidStatViewServletConfiguration.class:監控頁的配置:spring.datasource.durid.stat-view-servlet,默認開啟,
    4.DruidWebStatFilterConfiguration.class:web監控的配置:spring.datasource.durid.web-stat-filter,默認開啟,
    5.DruidFilterConfiguration.class:所有Druid都有自己filter的配置,

2.3.3 整合mybatis

  • 引入第三方starter,
  • 撰寫Mapper介面,標注@Mapper注解,
  • 撰寫sql映射檔案并系結Mapper介面,
  • 在application.yaml中指定Mapper組態檔的位置,以及指定全域組態檔的資訊,【建議全域組態檔的配置配置在application.yaml的mybatis.coniguration下就行】,
<!--第三方starter-->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.4</version>
</dependency>

引入的依賴

  1. 配置模式
    1.全域組態檔,
    2.SqlSessionFactory:自動配置好了,
    3.SqlSession:自動配置了SqlSessionTemplate組合了SqlSession,
    4.@Import(AutoConfiguredMapperScannerRegisterar.class)
    5.Mapper:只要我們寫的操作Mybatis的介面標注了 @Mapper就會被自動掃描進來,【可以用 @MapperScan來掃描Mapper,代替@Mapper】

    #配置mybatis規則
    #Mapper介面系結xml
    mybatis:
     	config-location:                 #全域組態檔
     	mapper-location:				 #sql映射檔案位置
    
  2. 注解模式
    @Select:寫查詢陳述句,
    @Insert:寫插入陳述句,
    @Options:寫陳述句的屬性項,

  3. 混合模式

2.3.4 整合Mybatis-Plus完成CRUD

什么是Mybatis-Plus:是一個Mybatis的增強工具,為簡化開發提高效率而生,建議安裝MybatisX插件,

引入mybatis-plus

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>Latest Version</version>
</dependency>

自動配置:

  • MybatisPlusAutoConfiguration配置類,MybatisPlusProperties配置項系結,mybatis-plus:xxx就是對mybatis-plus的定制,
  • SQLSessionFactory自動配置好,底層是容器中默認的資料源,
  • mapperLocation自動配置好,有默認值,classpath*:/mapper/**/*.xml;任意包的類路徑下的所有Mapper檔案夾下的任意路徑的所有xml都是映射檔案,建議以后sql所有映射檔案都寫在mapper下,
  • 容器中也自動配置好了SqlSessionTemplate,
  • @Mapper標注的介面也會被自動掃描,建議寫@MapperScan批量掃描就行,

優點:

  • 只要我們的Mapper繼承BaseMapper,就可以擁有crud能力,
  • 使用 @TableField可以標注屬性是否存在于資料表中,
  • 使用 @TableName可以指定資料庫中對應資料表名字,
  • 在Service介面中繼承IService,
  • 在ServiceImplement中繼承ServiceImpl,

2.3.5 NoSql(以Redis為例)

引入依賴:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

自動配置:

  • RedisAutoConfiguration自動配置類,RedisProperties屬性類—>spring.redis.xxx是對Redis的配置,
  • 連接工廠是準備好的,LettuceConnectConfiguration、JedisConnectConfiguration,
  • 自動注入了RedisTemplate<Object,Object>:xxxTemplate,
  • 自動注入了StringRedisTemplate;k,v都是String,
  • key:value,
  • 底層只要我們使用RedisTemplate或者StringRedisTemplate就可以操作Redis,

Redis環境搭建:

  • 使用阿里云按量付費Redis,經典網路,
  • 申請Redis的公網連接地址,
  • 修改Redis白名單【0.0.0.0/0】,

RedisTemplate與Lettuce:
application.yaml中配置spring.redis.host、spring.redis.port、spring.redis.password,
連接redis切換到jedis:

  • 添加redis和jedis的依賴
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<dependency>
	<groupId>redis.clients</groupId>
	<artifactId>jedis</artifactId>
</dependency>
  • application.yaml中配置spring.redis.host、spring.redis.port、spring.redis.password、spring.redis.client-type:jedis,

2.4 單元測驗

2.4.1 JUnit變化及與SpringBoot整合

JUnit5:

  • JUnit Platform:是在JVM啟動測驗框架的基礎,不僅支持JUnit自制的測驗引擎,其他測驗引擎也可以接入,
  • JUnit Jupiter:提供了JUnit5的新的編程模型,是JUnit5新特性的核心,內部包含了一個測驗引擎在JUnit Platform運行,
  • JUnit Vintage:提供了兼容JUnit4.x,JUnit3.x的測驗引擎,

注意:

  • SpringBoot2.4及其以上版本移除了默認對Vintage的依賴,如果需要使用JUnit4需要自行引入,(不能使用JUnit4的功能 @Test),
  • 在SpringBoot使用Junit4及以前版本需要在測驗類標注 @SpringBootTest@RunWith(SpringTest.class)
  • 在SpringBoot使用JUnit5只需要在測驗類中標注 @SpringBootTest

SpringBoot整合JUnit后:

  • 撰寫測驗方法:@Test標注(注意需要使用Junit5版本的注解),
  • Junit類具有Spring功能,可以使用@Autowired、@Transaction【測驗完成后會自動回滾】注解,

2.4.2 JUnit5常用注解

@DisplayName:為測驗類或者測驗方法展示名稱,

@DisplayName("測驗displayName方法")
@Test
void testDisplayName(){
	System.out.println(1);
}

@BeforeEach:在每個測驗單元測驗之前執行,

@BeforeEach
void testBeforeEach(){
	System.out.println("當前測驗之前執行");
}

@AfterEach:在每個測驗單元測驗之后執行,

@BeforeEach
void testAfterEach(){
	System.out.println("當前測驗之后執行");
}

@BeforeAll:在所有測驗單元測驗之前執行,

//因為只執行一次,所有方法之前要加上static
@BeforeAll
static void testBeforeAll(){
	System.out.println("所有測驗之前執行");
}

@AfterAll:在所有測驗單元測驗之后執行,

//因為只執行一次,所有方法之前要加上static
@AfterAll
static void testAfterAll(){
	System.out.println("所有測驗之后執行");
}

@Tag:表示單元測驗類別,相當于JUnit4的 @Categories
@Disable:表示測驗類或測驗方法不執行,類似于JUnit4的 @Ignore
@Timeout:表示測驗方法運行如果超過了指定時間將會回傳錯誤,
@Timeout方法使用@RepeatedTest:測驗重復測驗的次數,

2.4.3 斷言

斷言是測驗中的核心部分,用來測驗需要滿足的條件進行驗證,這些斷言方法都是靜態方法,用來檢查業務邏輯回傳的資料是否合理,所有測驗運行結束后會有一個詳細的測驗報告,
斷言失敗后,后面的代碼都不會執行,
斷言有以下分類:

  1. 簡單斷言
  • assertEquals:判斷兩個物件或兩個原始型別是否相等,
@Test
@DisplayName("測驗簡單斷言")
void testSimpleAssertions(){
	int cal=cal(2,3);
	//可以自定義失敗資訊
	assertEquals(5,cal,"業務邏輯計算失敗");
}

int cal(int a,int b){
	return a+b;
}
  • assertNotEquals:判斷兩個物件或兩個原始型別是否不相等,
  • assertSame:判斷兩個物件參考是否指向同一個物件,
  • assertNotSame:判斷兩個物件參考是否指向不同物件,
  • assertTrue:判斷給定的布林值是否為True,
  • assertFalse:判斷給定的布林值是否為False,
  • assertNull:判斷給定的物件參考是否為Null,
  • assertNotNull:判斷給定的物件參考是否不為Null,
  1. 陣列斷言
  • assertArrayEquals:判斷兩個物件或者原始型別陣列是否相等,
  1. 組合斷言
  • assertAll:只有組合斷言中的所有斷言都成功,才算成功,
@Test
@DisplayName("測驗組合斷言")
void testAll(){
	assertAll(
		"testAll";
		()->assertEquals(5,5,"結果不是5"),
		()->assertTrue(true,true,"結果不為True"));
}
  1. 例外斷言
  • assertThrows:斷定業務邏輯一定出現例外,
@Test
@DisplayName("測驗例外斷言")
void testException(){
	assertThrows(
		ArithmeticException.class,
		()->{
			int i=10/0;
		},
		"業務邏輯居然正常");
}

//結果為:測驗通過
  1. 超時例外
  • assertTimeout:測驗方法有無超時,
@Test
@DisplayName("測驗超時斷言")
void testTimeout(){
	assertTimeout(
		Duration.ofMillis(1000),
		()->Thread.sleep(500)
	);
}
  1. 快速失敗
  • fail:直接使得測驗失敗,
@Test
@DisplayName("測驗快速斷言")
void testFail(){
	fail("is should fail");
}

2.4.4 前置條件(assumption)

前置條件:assumption【假設】類似于斷言,不同之處是在于不滿足的斷言會使得測驗方法失效,而不滿足的前置條件只會使得測驗方法的執行終止,前置方法可以看作測驗方法的前提,當該前提不滿足時,沒有繼續的必要,

2.4.5 嵌套測驗

  • 通過Java中的內部類和 @Nested注解實作嵌套測驗,
  • 嵌套測驗情況下,外層的的Test不能驅動內層的Before(After)All/Each之類的方法運行,而內層的可以驅動外層的,


import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.EmptyStackException;
import java.util.Stack;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

@DisplayName("A stack")
class TestingAStackDemo {

    Stack<Object> stack;

    @Test
    @DisplayName("is instantiated with new Stack()")
    void isInstantiatedWithNew() {
        new Stack<>();
    }

    @Nested
    @DisplayName("when new")
    class WhenNew {

        @BeforeEach
        void createNewStack() {
            stack = new Stack<>();
        }

        @Test
        @DisplayName("is empty")
        void isEmpty() {
            assertTrue(stack.isEmpty());
        }

        @Test
        @DisplayName("throws EmptyStackException when popped")
        void throwsExceptionWhenPopped() {
            assertThrows(EmptyStackException.class, stack::pop);
        }

        @Test
        @DisplayName("throws EmptyStackException when peeked")
        void throwsExceptionWhenPeeked() {
            assertThrows(EmptyStackException.class, stack::peek);
        }

        @Nested
        @DisplayName("after pushing an element")
        class AfterPushing {

            String anElement = "an element";

            @BeforeEach
            void pushAnElement() {
                stack.push(anElement);
            }

            @Test
            @DisplayName("it is no longer empty")
            void isNotEmpty() {
                assertFalse(stack.isEmpty());
            }

            @Test
            @DisplayName("returns the element when popped and is empty")
            void returnElementWhenPopped() {
                assertEquals(anElement, stack.pop());
                assertTrue(stack.isEmpty());
            }

            @Test
            @DisplayName("returns the element when peeked but remains not empty")
            void returnElementWhenPeeked() {
                assertEquals(anElement, stack.peek());
                assertFalse(stack.isEmpty());
            }
        }
    }
}

2.4.6 引數化測驗

  • 引數化測驗時Junit5的一個很重要的特性,它使得使用不用的引數多次運行測驗成為了可能,給單元測驗帶來了遍歷,
  • 利用@ValueSource等注解指定入參,我們就可以使用不同的引數進行多次測驗,不用每新增一個引數就多寫一個方法,就省去很多的冗余代碼,
  • 使用 @ParamsterizedTest表明該方法為引數化測驗的方法,
  • @ValueSource:為引數測驗指定入參,支持八大基礎型別、String型別及class型別,
@ParamsterizedTest
@DisplayName("引數化測驗1")
@ValueSource(ints={1,2,3,4,5})
void testParamsterizedTest1(int i){
	System.out.println(i);
}
  • @NullSource:表示為引數化測驗提供一個Null的入參,
  • @EnumSource:表示為引數化測驗提供一個列舉入參,
  • @CsvFileSource:表示讀取指定CSV檔案內容作為引數化測驗入參,
  • @MethodSource:表示讀取指定函式的回傳值作為引數化測驗入參,
@ParamsterizedTest
@DisplayName("引數化測驗2")
@MethodSource("stringProvider")
void testParamsterizedTest2(String i){
	System.out.println(i);
}

static Stream<String> stringProvider(){
	return Stream.of("apple","pear","cry");
}

2.4.7 Junit5遷移到JUnit4

參照JUnit官方檔案:https://junit.org/junit5/docs/current/user-guide/#migrating-from-junit4

2.5 指標控制

2.5.1 SpringBoot Actuator

2.5.1.1 簡介

SpringBoot Actuator:SpringBoot抽取Actuator場景,使得我們每個微服務都可以快速應用應用監控、審計等功能,

匯入starter:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

引入的依賴

2.5.1.2 1.x與2.x的不同

1.x與2.x的不同

2.5.1.3 如何使用
  • 引入場景
  • 訪問http://localhost:8080/actuator/**
  • 暴露所有監控資訊為HTTP
management:
	endpoints:
		enable-by-default: true    #暴露所有端點資訊
		web:
			exposure:
				include: '*'	#以web方式暴露
  • 測驗【http://localhost:8080/actuator/監控端點名/詳細要監控的路徑】
    http://localhost:8080/actuator/beans
    http://localhost:8080/actuator/metrics
2.5.1.4 可視化

https://github.com/codecentric/spring-boot-admin

  1. 創建SpringBoot快速向導專案作為可視化平臺專案,引入場景,

引入場景

  1. 在主入口類上標注 @EnableAdminServer
  2. 在客戶端【被監測微服務模塊】引入客戶端場景
    引入客戶端開發場景
  3. 在客戶端的application.yaml中配置spring.boot.admin.client.url=監控專案的地址
spring:
	boot:
		admin:
			client:
				url: http://localhost:8888	#此為監控端ip
				instance:
					prefer-ip: true	#使用IP注冊進來,默認值為false
	application:
		name: boot-01-admin	#設定專案名

2.5.2 Actuator Endpoint

2.5.2.1 最常用的端點

常用端點一
常用端點二
如果應用程式是Web應用程式,還可以使用以下:
web常用
最常用的Endpoint:

  • Health:監控狀況,
  • Metrics:運行時指標,
  • Loggers:日志記錄,
2.5.2.2 Health Endpoint

健康檢查端點,用于云平臺,定時檢查應用的健康狀況,我們就需要Health Endpoint為平臺回傳當前應用的一些列組件健康狀況的集合,

注意:

  • health Endpoint的回傳結果,應該是一系列健康檢查的匯總報告【up/down】,
  • 很多健康檢查已經默認配置好了,如redis、資料庫,
  • 可以添加自定義的健康檢查機制,
  • 可以在application.yaml中配置展示health endpoint的詳細資訊,
#management.endpoints:對所有端點進行配置
#management.endpoint: 對某個端點進行配置
management:
	endpoint:
		health:
			show-details: always
2.5.2.3 Metrics Endpoint

提供詳細的、層級的、空間指標資訊,這些資訊可以被pull(主動推送)或push(被動獲取)的方式獲得,

  • 通過Metrics對接多種監控系統,
  • 簡化核心Metrics開發,
  • 添加自定義的Metrics或者擴展已有的Metrics,
  • 需要獲取Metrics中的某項指標的詳細內容,還需要二次請求獲取,【http://localhost:8080/actuator/metrics/具體指標】
2.5.2.4 管理Endpoint

由于某些端點比較敏感,所有有時候要按需開啟端點,方法如下:

management:
	endpoints:
		enable-by-default: false    #關閉所有端點資訊
		web:
			exposure:
				include: '*'	#以web方式暴露
	endpoint:
		health:
			show-details: always
			enable: true

		info:
			enable: true
			
		beans:
			enable: true	
				
		metrics:
			enable: true

2.5.3 定制Endpoint

2.5.3.1 定制Health資訊
  • 方式一:實作HealthIndicator介面
  • 方式二:繼承AbstractHealthIndicator抽象類
//繼承AbstractHealthIndicator抽象類

@Component
public class MyComHealthIndicator extends AbstractHealthIndicator{
	@Override
	protect void doHealthCheck(Health.Builder builder) throws Exception{
	
		//mongodb.進行連接測驗

		//存盤詳細資料
		Map<String,Object> map=new HashMap<>();
		
		//進行檢查業務邏輯
		if(1=1){
//			builder.up();	//方式一:健康
			builder.status(Stauts.UP);	//方式二:取具體的狀態Stauts.UP
			map.put("count",1);
			map.put("ms",100);
		}else{
//			builder.down();
			builder.status(Stauts.OUT_OF_SERVICE);	//方式二:取具體的狀態Stauts.OUT_OF_SERVICE
			map.put("err","連接超時");
			map.put("ms",300);
		}

		//withDetail()放鍵值對
		//withDetails()放Map<String,Object>
		builder.withDetail("code",100)
			   .withDetails(map);
	}
}
2.5.3.2 定制Info資訊
  • 方式一:撰寫application.yaml組態檔
info:
	##在application.yaml寫死
	appName: boot-gul
	version: 2.0.2
	
	#使用@@獲取maven的pom檔案的值
	mavenProjectName: @project.artifactId@
	mavenProjectVersion: @project.version@
  • 方式二:實作InfoContributor介面
//實作InfoContributor介面
@Component
public class AppInfoInfoContributor implements InfoContributor{
	@Override
	public void contribute(Info.Builder builder){
		builder.withDetail("msg","hello")
			   .withDetails(Collections.singletonMap("time","20200000"));
	}
}
2.5.3.3 定制Metrics資訊
  • 方式一:在需要呼叫的類中創建一個構造武,傳入MeterRegistry引數,并呼叫meterRegistry的具體方法,
class MyService{
	Counter counter;
	public Myservice(MeterRegistry meterRegistry){
		counter=meterRegistry.counter("myService.method.running.counter");
	}

	public void hello(){
		counter.increament();
	}
}

-方式二: 注冊Bean
注冊bean

2.5.3.4 定制Endpoint
@Compoment
@Endpoint(id="myservice")
public class DockerEndpoint{

	@ReadOperation
	public Map getDockerInfo(){
		return Collection.singletonMap("info","docker start...");
	}

	@WriteOpertion
	public void restartDocker(){
		System.out.println("docker stop...");
	}
}

2.6 原理決議

2.6.1 Profile

2.6.1.1 application-profile功能
  • 默認配置環境application.yaml在任何時候都會加載,
  • 指定環境組態檔命名規則:application-{env}.yaml,
  • 激活指定環境:
    1.默認的組態檔中激活:spring.profiles.active= yyy
    2.命令列激活【更靈活,在打包之后還可以激活,且組態檔中所有的配置項都可以改變】:java -jar xxx.jar --spring.profiles.active= yyy
  • 默認配置和環境配置同時生效,
  • 同名配置項,profile配置優先,
2.6.1.2 @Profile條件裝配功能

@Profile可以在類上或方法上使用,

@Profile("prod")
public class prodEnv(){
	
	//...
	
}
2.6.1.3 profile配置分組

在默認配置的application.properties中配置分組,

<!--先宣告分組-->
spring.profiles.group.myprod[0]=prod0
spring.profiles.group.myprod[1]=prod1

<!--激活環境-->
spring.profiles.active=myprod

2.6.2 外部化配置

2.6.2.1 外部配置源

常用:Java屬性檔案、yaml檔案、環境變數、命令列引數,

1.Default properties (specified by setting SpringApplication.setDefaultProperties).

2.@PropertySource annotations on your @Configuration classes. Please note that such property sources are not added to the Environment until the application context is being refreshed. This is too late to configure certain properties such as logging.* and spring.main.* which are read before refresh begins.

【3.Config data (such as application.properties files)】組態檔application.properties、application.yaml

4.A RandomValuePropertySource that has properties only in random.*.

5.OS environment variables.

6.Java System properties (System.getProperties()).

7.JNDI attributes from java:comp/env.

8.ServletContext init parameters.

9.ServletConfig init parameters.

10.Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property).

【11.Command line arguments.】命令列引數
  1. properties attribute on your tests. Available on @SpringBootTest and the test annotations for testing a particular slice of your application.
13.@TestPropertySource annotations on your tests.

14.Devtools global settings properties in the $HOME/.config/spring-boot directory when devtools is active.
2.6.2.2 組態檔查找順序

至上而下查找,后面的會覆寫前面的,

  1. classpath根路徑,
  2. classpath根路徑下的config目錄,
  3. jar包當前目錄,
  4. jar包當前目錄的config目錄,
  5. /config子目錄的直接子目錄,

【2.6.2總結:指定環境優先,外部配置優先】

總結篇

學習程序中難免會接觸到一些原始碼的決議,但也可以整體把握好SpringBoot的基本應用,回頭再來理解好原始碼,這樣便于減少枯燥,保持學習興趣,后續的SpringBoot一些核心技術的學習還包括虛擬化技術、安全控制、快取技術、訊息中間件、物件存盤、定時調度、異步任務、分布式系統等,以及SpringBoot的回應式編程,包括回應式編程基礎、Weflux開發web應用、回應式訪問持久層、回應式安全開發和回應式原理,

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/266363.html

標籤:java

上一篇:Java 基礎面試題整理,希望也能幫到你

下一篇:Java常用注解(Annotation)詳解匯總

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more