說明
本文樣例說明僅適用 maven
環境和語法,但所述內容也適用 gradle
原文地址:https://www.cnblogs.com/qnlcy/p/15905544.html
一、日志
1. logback
日志默認為 slf4j
+ logback
框架,引入如下 jar 之后,就自動引入了 logback
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
默認配置文件名稱如下,在 classpath
目錄下存在對應文件名即可,無需額外通過配置指定
- logback-spring.xml (官方推薦,可以添加 spring boot 的
springProfile
配置項) - logback.xml
2. log4j2
請在大流量應用當中使用 log4j2
而不是使用 log4j
,log4j
在並發寫文件上有嚴重的性能問題,而且,她已經退役了。
首先要排除默認日志框架 logback
,如下為樣例代碼
請不要照抄到項目當中而帶來不必要的
spring-boot-starter-web
及其系列 web 功能的引用
你需要掌握的是如何排除一個 jar 和引入另外一個 jar
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
默認配置文件名稱如下,同樣在 classpath
目錄下存在對應文件名即可,無需額外通過配置指定
- log4j2-spring.xml(官方推薦,可以添加 spring boot 的
springProfile
配置項) - log4j2.xm
二、項目配置文件
1. 配置文件路徑
springboot 默認從如下位置加載配置文件,按 優先級
排序為
- 當前 jar 目錄下的
config
子目錄 - 當前 jar 目錄下的
config/*
目錄,注意,此時會合並config
的子目錄下的所有application
配置文件 - 當前 jar 目錄
classpath
下的config
目錄classpath
目錄
找尋的 默認配置文件
名稱,優先級
為:
- application.properties
- application.yml
- application.yaml
相同配置屬性下,優先級高的配置會覆蓋優先級低的配置,但是不同的配置屬性會合並
比如,在 applicaiton.properties
里有:
name=qnlcy
在 application.yml
里有:
name: cnblog
age: 18
這時候,spring 讀取到的 name
和 age
值分別為 qnlcy
和 18
2. 環境配置
指定 spring 加載的環境,可以使用如下配置
yml / yaml
spring:
profiles:
active: dev
properties
spring.profiles.active=dev
命令行參數形式
-Dspring.profiles.active=dev
#或
--spring.profiles.active=dev
然后 spring 會在 上述 第1小節 配置文件目錄
下,同樣 優先
查找對應的如下文件
- application-${profiles}.properties
- application-${profiles}.yml
- application-${profiles}.yaml
對應上述配置,找尋的配置文件即為:application-dev.properties
或 application-dev.yml
或 application.yaml
三、spring默認依賴介紹和項目划分
項目可以粗略划分為
- web 項目
- 非 web 項目
兩種類型的項目,如果使用 spring 管理依賴版本,則 pom.xml 需要加上 <parent>
相關配置:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.5.RELEASE</version>
</parent>
這里默認使用 spring 管理依賴版本,各個項目也應當繼承 spring-boot-starter-parent
, 下面不再寫各個依賴的版本
1. 非web項目
先說下非 web 項目,非 web 項目使用 springboot,只需要引入如下 jar 即可
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
它顯式依賴如下包:
spring-boot
springboot項目核心包spring-boot-autoconfigure
springboot項目的自動配置包,包含datasource、http、session等等等自動配置相關代碼spring-boot-starter-logging
springboot項目的日志包,默認實現為logback
spring-core
spring核心包
其中,spring-boot-autoconfigure
又自動依賴 spring-boot
spring-boot
依賴 springframework
的系列包,其依賴及其子依賴分別為
spring-context
spring-beans
spring-core
spring-aop
spring-expresion
2. web項目
web項目引用如下 jar 即可
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
它顯式依賴了如下 jar
spring-boot-starter
spring-boot-starter-json
這里引入 jacksonspring-boot-starter-tomcat
默認內置 tomcat,切換web容器時候需要排除此包spring-webmvc
spring-web
傳統的 dubbo
服務提供者項目、RocketMq
消息消費服務、批處理服務,就不要再引用 spring-boot-starter-web
包了,它默認會引入 web 容器,並開放 web 服務和端口,這是危險和不必要的
四、springboot 啟動類和其注解
1. 啟動類
springboot 的啟動類不能直接放在 src/main/java
目錄下,即:
springboot 的啟動類的
包路徑
不能為空
如果這樣做的話,會出現意想不到的錯誤,感興趣的同學可以試一下。
通常的,我們會把啟動類放到諸如 com.xxx.xxx
之類頂級路徑下,如:com.xxx.xxx.App.class
然后再在頂級路徑下新建如 config
、business
、utils
、constant
、enums
之類的包,結構如下:
com.xxx.xxx
+ config/
+ business/
+ utils/
+ constant/
+ enums/
App.class
spring 默認會自動掃描啟動類的同級目錄及其子目錄
下的 spring bean 定義,並裝載到 spring 容器當中
因此,如果要引用外部包內的 spring bean ,則需要通過如下方式告知包掃描路徑給 spring
@SpringBootApplication
@ComponentScan({"com.xxx.yyy","com.xxx.zzz"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
其中,com.xxx.zzz
為風控 jar 包的路徑,在注解 @ComponentScan
當中添加該路徑,即可使用該 jar 包內的 spring bean 組件
2. 啟動類注解
通常,springboot 啟動類注解只需要一個 @SpringBootApplication
即可,觀其定義,可以發現,它自動包含了 @ComponentScan
、@EnableAutoConfiguration
等注解,已經包含 包掃描
、自動配置
功能
//...
@EnableAutoConfiguration
@ComponentScan(
//...
)
public @interface SpringBootApplication {
//...
}
關於 dubbo
如果使用 dubbo 包里的 @Service (注意不是 spring 的 @Service)
、@Reference
來暴露和引用服務,則需手動開啟 dubbo 功能,來使 dubbo 掃描到上述注解開啟的 dubbo 服務
@SpringBootApplication
@EnableDubbo
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
如果 dubbo 服務不在當前項目路徑下,則額外添加
@DubboComponentScan({"com.xxx.xxx"})
注解來指定 dubbo 掃描路徑
通常我們使用 xml
配置文件的形式來歸納 dubbo 的相關服務,此時,只要在 spring 啟動時候,把 dubbo bean 相關配置引入到 spring 容器中即可。
常用做法如下,定義個 springboot 配置類來導入 dubbo bean
@Configuration
@ImportResource({"classpath:dubbo/config.xml", "classpath:dubbo/consumer.xml", "classpath:dubbo/provider.xml"})
public class DubboConfig {
}
關於事務
如果引用了 spring-jdbc
並且配置了 DataSource
,則 springboot 默認會開啟事務支持,不需要再使用 @EnableTransactionManagement
顯式開啟事務了
五、MVC中的錯誤處理
在 web 項目當中,springboot 對異常粗略划分,可以有如下處理
- 使用
@ControllerAdvice
+@ExceptionHandler
來處理已到達controller層級的業務異常 - 自定義 error controller 來處理其他系統級異常
感興趣的同學可以追蹤 DispatcherServlet.doDispatch()
方法來查看具體錯誤處理過程
1. ControllerAdvice 的用法
在項目當中,使用 @ControllerAdvice
注解指定一個 異常處理器
,它自動交給了 spring 管理,其本質是一個 spring bean
@ControllerAdvice
public class ExceptionResolver {
//因為是 spring bean,所以可以注入自己需要的資源
@ExceptionHandler(value = BusinessException.class) //指定攔截的異常
@ResponseBody //指定返回頁面為json串
//方法名可以自定義,但參數不能變,可選參數尚有 HttpServletRequest
public String businessExceptionHandler(HandlerMethod handlerMethod, Exception e) throws Exception {
//處理異常
}
//可以定義多個異常處理方法,spring 會自動尋找對應的異常處理器
//切記最后要有一個處理Exception的兜底
@ExceptionHandler(value = Exception.class)
@ResponseBody
public String defaultErrorHandler(HandlerMethod handlerMethod, Exception e) throws Exception {
}
}
2. 自定義 error controller 來處理其他系統級異常
在出現 controller 層級之外的異常之后,springboot加載的內置容器會轉發異常到 springboot 指定的 errorPath
路徑上,默認為 /error
,可以通過如下配置修改
server.error.path=/err1
轉發過來的請求可以這樣處理
@Controller
@RequestMapping("/err1") //上述定義的錯誤路徑
public class CustomErrorController{
@RequestMapping(produces = "text/html")
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
//request中含有 狀態碼 和 錯誤信息
return new ModelAndView("500.html");
}
}
六、JSON
springboot 支持三種 JSON 框架,默認為 Jackson
1. Jackson
當項目當中引入了 spring-boot-starter-json
包后, springboot 會自動創建一個 ObjectMapper
bean 來使用。可以通過 spring.jackson
的相關配置來 定義該 bean,祥見 org.springframework.boot.autoconfigure.jackson.JacksonProperties
類
2. Gson
當項目當中引入了 Gson
包后,springboot 會自動創建一個 Gson
bean。通過 spring.gson
的相關配置或 GsonBuilderCustomizer
來定義該 bean
3. JSON-B
JSON-b 是一種 json api 規范,當 javax.json-api
jar包存在項目當中,並且其實現類也存在,Springboot就會創建一個 Jsonb
來使用。這種不常見,不再介紹。
七、測試
1. 單元測試
使用單元測試,需引用 spring-boot-starter-test
,並指定其范圍為 test
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<!-- 如果是junit5 則排除如下依賴 -->
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
maven 管理的依賴對其 scope 做了划分,有如下幾種
編譯 | 測試 | 打包 | 運行 | 說明 | |
---|---|---|---|---|---|
compile | √ | √ | √ | √ | 默認的范圍 |
test | √(測試代碼) | √ | × | × | 如:junit |
runtime | × | √ | √ | √ | 如:jdbc驅動 |
provided | √ | √ | × | × | 運行時使用別的包代替,如:servlet-api,在tomcat容器中已有此包 |
system | √ | √ | × | × | 跟provided相同,只不過從本地文件系統拉包,而不是從maven倉庫(本地和遠程)拉取 |
創建 test 類,使用 @SpringBootTest
注解來聲明該類為測試類
//@@RunWith(SpringRunner.class) 如果使用 junit4 則需要添加此注解,junit5 則不再需要
@SpringBootTest //不用再指定啟動類,springboot 會自動找到啟動類並啟動 spring
public class PaHttpServiceTest {
//可以正常引用其他 spring 資源
//方法必須為public,返回值必須為 void , junit5 可以不寫 public
@Test
public void testHttp() {
//
}
}
2. benchmark 基准測試
此類測試為代碼性能測試服務,不適用與業務測試。此類測試會分析每個基准測試方法的單位時間吞吐量、執行耗時等,方便我們提升自己代碼的性能。
引入相關依賴
<!-- JMH-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<encoding>UTF-8</encoding>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<jmh.version>1.21</jmh.version>
</properties>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>${jmh.version}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
<scope>provided</scope>
</dependency>
創建測試類,main 方法執行,所有被注解 @Benchmark
標注的方法都會進行性能測試
@BenchmarkMode(Mode.Throughput) //基准測試類型。這里選擇的是吞吐量
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) //預熱,輪數:5輪,每次預熱時間:1,單位:秒(默認)
@Measurement(iterations = 10, time = 5, timeUnit = TimeUnit.SECONDS) //進行10輪測試,每次時間:5,單位,秒
@Threads(8) //一般CPU*2 每個fork所用的線程數量
@Fork(2) //JMH分出2個 “進程”進行測試
@OutputTimeUnit(TimeUnit.NANOSECONDS) //基准測試結果里面的時間類型
public class StringAppend {
public static void main(String[] args) throws RunnerException {
Options options = new OptionsBuilder()
.include(StringAppend.class.getSimpleName())
.build();
new Runner(options).run();
}
@Benchmark
public void testStringAdd() {
String a = "";
for (int i = 0; i < 10; i++) {
a += i;
}
}
}
下面測試結果說明,平均每納秒,能執行4次
方法名 | 測試類型 | 測試次數 | 得分 | 錯誤 | 單位 |
---|---|---|---|---|---|
StringAppend.testStringAdd | thrpt | 4 | 0.010 | ± 0.001 | ops/ns |