Spring

單例bean是否線程安全

spring中的bean由@Scope註解定義是否為單例

  • @Scope(“singleton”) 單例,默認
  • @Scope(“prototype”) 多例

因此spring中bean默認單例

但單例bean也可能會導致線程不安全

這需要看bean有無狀態

  • 有狀態:類中有可被修改的成員變量(通常是我們自己手動添加了成員變量)
  • 無狀態:類中無可被修改的成員變量(例如通常情況下自動注入的service、mapper等bean,它們不可被修改)

若bean有狀態,多線程訪問時都對這個成員變量進行修改,就可能導致線程安全

此時我們可以通過

  • 多例(資源不共享)
  • 加鎖(資源共享,但互斥訪問)

來解決線程安全問題

AOP

作用:減少重複代碼、抽取公共模塊降低耦合

常用場景:

  • 記錄日誌
  • 緩存處理
  • 事務處理

使用:

  • 定義切面類(bean管理、@Aspect)
  • 定義切入點(可通過類路徑、註解指定切入位置)
  • 定義通知(常用環繞通知)

spring事務也基於AOP實現

事務

spring事務也基於AOP實現

作用:讓代碼同成功同失敗

使用:方法上添加@Transactional

失效場景:

  • 異常被手動捕獲(沒拋出,spring事務框架就不知道要回滾)
  • 拋出檢查異常(spring默認只回滾非檢查異常,即只回滾RunTimeException)

通過@Transactional(rollbackFor = Exception.class)即可解決

  • 非public修飾的方法(spring只給public方法創建代理、添加事務通知)

bean生命週期

無論是通過在xml中定義bean信息,還是通過註解定義bean信息

在創建bean前,spring都會先將bean信息封裝成BeanDefinition對象,作為後續創建bean的依據

流程:

  1. 實例化(依據BeanDefinition調用構造函數,創建初始bean)
  2. 初始化
  • 依賴注入(注入成員變量,包括存儲值的普通成員變量、依賴的其他bean)
  • Aware接口(實現以下三個接口,並實現對應方法,方法中的代碼會依次執行)
  • BeanNameAware
  • BeanFactoryAware
  • ApplicationContextAware
  • BeanPostProcessor#before(和後面那個after一樣,定義在另一個實現了BeanPostProcessor類(記得註冊為bean)中,實現before、after方法,方法中的代碼會依次執行)
  • 初始化方法
  • InitializingBean(實現對應接口和方法,操作和Aware一樣)
  • 自定義init方法(@PostConstruct修飾的方法)
  • BeanPostProcessor#after(常用作AOP的位置)
  1. 銷燬(銷燬前執行@PreDestroy修飾的方法)

BeanPostProcessor相對於Aware接口

  • 前者相當於全局處理器,定義在外部,可作用於所有符合條件的bean
  • 後者乃至大部分初始化步驟,只針對實現了對應接口、或者使用了對應註解的bean自身

bean循環依賴

循環依賴:兩個或多個Bean相互依賴(如A依賴B,B依賴A)

主要作用在bean生命週期的屬性注入階段

通過spring三級緩存解決

  • 一級:已經初始化完成的bean對象
  • 二級:提前暴露的 “半成品” 單例 Bean 實例(存由三級工廠創建的對象)
  • 三級:用於創建 “提前暴露” 的 Bean 實例的 Bean 工廠

簡單流程如下:

  1. 實例化:通過構造器創建 Bean 的原始對象(此時對象已存在,但屬性未注入,初始化未完成)
  2. 提前暴露:將剛實例化的原始對象放入三級緩存,供其他依賴它的 Bean 提前引用
  3. 依賴注入:
  • Spring 嘗試為當前 Bean 注入依賴(如,A 實例化後,注入依賴 B)
  • 若 B 尚未創建,則觸發 B 的實例化流程
  • 當 B 實例化後,注入依賴 A 時,會從三級緩存中獲取 A 的提前暴露實例,避免 A 重複創建,從而解決循環依賴

但若依賴注入的方式是構造函數注入,因為實例化第一步就調用構造函數,因此spring無法通過三級緩存解決循環依賴問題,此時就需要添加@Lazy註解,讓bean對象懶加載

SpringMVC

執行流程

  1. 用户發出請求到DispatcherServlet(前端控制器)
  2. DispatcherServlet調用HandlerMapping(處理器映射器)
  3. HandlerMapping找到具體的處理器並將處理器對象返回給DispatcherServlet
  4. DispatcherServlet調用HandlerAdapter(處理器適配器)
  5. HandlerAdapter調用具體的處理器
  6. 處理器添加了@ResponseBody
  7. 通過HttpMessageConverter將返回結果轉為JSON並響應

SpringBoot

自動配置原理

啓動類有註解@SpringBootApplication

該註解包含:

  • @SpringBootConfiguration
  • @EnableAutoConfiguration
  • @ComponentScan

@EnableAutoConfiguration是實現自動配置的核心

其內部包含@Import會導入META-INF/spring.factories文件中所配置的類的全類名

被導入的配置類會自帶@Conditional等註解,符合條件則將配置類中的bean注入到spring容器中

常用註解

分類

註解名稱

作用説明

啓動類註解

@SpringBootApplication

Spring Boot 應用入口註解,組合了 @SpringBootConfiguration@EnableAutoConfiguration@ComponentScan,用於開啓自動配置和組件掃描

配置類註解

@Configuration

標識當前類為配置類,替代傳統 XML 配置文件,可通過 @Bean 定義 Bean

@Bean

用於 @Configuration 類中,聲明一個 Bean 實例,方法名默認作為 Bean 名稱

@PropertySource

加載指定的外部屬性文件(如 classpath:config.properties),配合 @Value 使用

@ConfigurationProperties

將配置文件中的屬性批量綁定到 Java 類(需配合 @Component@EnableConfigurationProperties 生效),支持前綴指定(如 prefix = "user"

組件掃描

@ComponentScan

指定組件掃描路徑,默認掃描當前類所在包及子包,可通過 basePackages 自定義路徑

@Component

通用組件註解,標識類為 Spring 管理的 Bean,通常用於非三層架構的普通組件

@Controller

標識 MVC 中的控制器(Controller),處理 HTTP 請求,返回視圖或數據

@RestController

組合 @Controller@ResponseBody,標識控制器方法返回 JSON/XML 等數據(無需視圖解析)

@Service

標識業務邏輯層(Service)組件

@Repository

標識數據訪問層(DAO)組件,自動轉換數據庫操作異常為 Spring 統一異常

依賴注入

@Autowired

自動注入依賴的 Bean,默認按類型匹配,可配合 @Qualifier 指定名稱

@Qualifier

@Autowired 配合,按名稱注入 Bean(解決同類型多個 Bean 的衝突)

@Resource

JDK 自帶註解,默認按名稱注入,無名稱時按類型匹配(與 @Autowired 功能類似)

@Value

注入配置文件中的單個屬性值(如 @Value("${app.name}")),支持 SpEL 表達式

MVC 映射

@RequestMapping

映射 HTTP 請求(URL、方法、參數等)到控制器方法,可用於類或方法上(類上定義公共路徑)

@GetMapping

簡化的 @RequestMapping(method = RequestMethod.GET),處理 GET 請求

@PostMapping

簡化的 @RequestMapping(method = RequestMethod.POST),處理 POST 請求

@PutMapping

處理 PUT 請求(通常用於更新資源)

@DeleteMapping

處理 DELETE 請求(通常用於刪除資源)

@ResponseBody

標識控制器方法返回結果直接寫入響應體(而非視圖),通常用於返回 JSON 數據

@RequestBody

將 HTTP 請求體(如 JSON)轉換為方法參數對象(適用於 POST/PUT 等請求)

@PathVariable

綁定 URL 路徑中的參數(如 /user/{id} 中的 id)到方法參數

@RequestParam

綁定請求參數(如 ?name=xxx)到方法參數,支持設置默認值、是否必傳等

@RequestHeader

綁定請求頭信息到方法參數(如 @RequestHeader("User-Agent")

條件註解

@Conditional

基於條件判斷是否創建 Bean 或導入配置類,需自定義 Condition 實現類

@ConditionalOnClass

當類路徑中存在指定類時,才生效(如 @ConditionalOnClass(DataSource.class)

@ConditionalOnMissingClass

當類路徑中不存在指定類時生效

@ConditionalOnBean

當容器中存在指定 Bean 時生效

@ConditionalOnMissingBean

當容器中不存在指定 Bean 時生效(常用於自動配置的 “默認 Bean”)

@ConditionalOnProperty

當配置文件中存在指定屬性且值匹配時生效(如 @ConditionalOnProperty(name = "feature.enabled", havingValue = "true")

AOP 相關

@Aspect

標識當前類為 AOP 切面類

@Pointcut

定義切入點(如 @Pointcut("execution(* com.example.service.*.*(..))")

@Before

前置通知,在目標方法執行前執行

@After

後置通知,在目標方法執行後(無論是否異常)執行

@AfterReturning

返回通知,在目標方法正常返回後執行

@AfterThrowing

異常通知,在目標方法拋出異常後執行

@Around

環繞通知,包裹目標方法,可控制方法執行時機(需顯式調用 proceed()

事務管理

@Transactional

標識方法或類需要事務管理,可配置隔離級別、傳播行為、超時時間等

測試相關

@SpringBootTest

用於 Spring Boot 測試類,自動加載應用上下文,支持模擬環境

@MockBean

在測試中替換容器中的 Bean 為 Mock 實例(通常配合 Mockito 使用)

Mybatis

執行流程

  1. 讀取mybatis配置文件,加載運行環境和xml(sql映射文件)
  2. 根據配置文件構建SqlSessionFactory(會話工廠)
  3. 每次操作數據庫前,SqlSessionFactory創建SqlSession對象
  4. 根據SqlSession創建mapper代理對象
  5. 調用mapper代理方法時調用Executor(執行器)生成Statement對象(包含sql、結果集等)
  6. 若成功則SqlSession提交事務,再關閉SqlSession

延遲加載

即需要用到數據時才加載

立即加載是,當我查詢一個表後,這個表關聯的其他表的內容也都查詢出來

例如:

user表和user_like表是一對多關係

實體類中user類中有屬性 List userLikes

如果是立即加載,則會將useLiskes的值也填充好,默認是立即加載

一二級緩存

作用:減少數據庫查詢次數,提升性能

本質:把已查過的數據暫存在內存中,後續再查相同數據時直接從緩存取,不用再訪問數據庫

一級緩存默認開啓,二級默認不開啓

一級針對SqlSession(避免同一會話重複查詢),二級針對SqlSessionFactory(即多個SqlSession共享緩存,多個請求走同一個緩存)