Spring整體結構:
Spring實際運行場景:
基礎
Spring啟動過程
傳統Spring:
(1)初始化準備階段
(2)容器創建與注入
(3)Bean工廠后置處理
(4)Bean工廠后置處理
(5)Bean實例化與依賴注入
(6)容器啟動完成
Spring Boot應用:
(1)啟動類觸發(@SpringBootApplication)
(2)初始化SpringApplication
(3)環境準備Environment
(4)創建ApplicationContext
(5)自動裝配(@EnableAutoConfiguration)
(6)Bean加載與初始化(同傳統Spring核心流程)
(7)Bean加載與初始化(同傳統Spring核心流程)
(8)Bean加載與初始化(同傳統Spring核心流程)
Spring的組成部分
- 核心容器模塊:核心包(spring-core)、上下文包(spring-context)、表達式語言包(spring-expression)
- 面向切面編程模塊:spring-aop、spring-aspects
- 數據訪問/集成模塊:spring-jdbc、spring-tx、spring-orm
- web模塊:spring-web、spring-webmvc、spring-websocket
- 測試模塊:spring-test
Spring的優勢
- 輕量級與低侵入性
- 強大的IoC與DI機制
- 面向切面編程AOP
- 豐富的模塊支持
- 良好的整合性
- 優秀的社區支持與生態系統
Spring運用了哪些設計模式
- 工廠模式:FactoryBean、BeanFactory和ApplicationContext
- 單例模式:默認Bean的作用域
- 代理模式:AOP的實現(基于JDK和CGLIB實現動態代理)
- 模板方法模式:數據庫操作模板(JDBCTemplate、RedisTemplate)
- 觀察者模式:事件驅動模型(ApplicationEvent和ApplicationListener)
- 適配器模式:在Spring AOP中用于增強或通知(Advice)的實現。適配不同的Controller實現類
- 裝飾器模式:BeanWrapper對Bean的增強(把配置文件中的字符串轉換為Bean的屬性類型)
- 策略模式:資源加載策略,ResourceLoader通過Resource接口的不同實現(ClassPathResource、FileSystemResource)
IoC
優勢:解耦對象依賴、統一管理對象的生命周期、便于擴展與復用、簡化測試
DI
DI與IOC的關系:
- IOC是思想:強調“控制權轉移”(容器管對象)。
- DI是手段:通過“注入依賴”的方式,實現IOC的思想落地。
簡單說:IOC 是“要解決什么問題”,DI 是“具體怎么解決”。
注入方式:構造器注入、Setter注入、字段注入
注入如何解決循環依賴問題(常見問題)
- 三級緩存:
- 一級緩存:用于存儲已經初始化完畢的單例Bean實例
- 二級緩存:存儲已經實例化但未完成屬性注入和初始化的單例Bean實例
- 三級緩存:存儲能夠生成單例Bean實例的工廠對象
為什么需要三級緩存?(常見問題)
- 依賴注入方式的選擇:構造器注入(會造成死鎖)、Setter注入
- 其他解決辦法:使用@Lazy注解、使用@PostConstruct注解、使用ApplicationContext獲取Bean、使用接口和事件機制
Bean
如何創建Bean?
- BeanFactory:核心接口,用于管理和提供Bean實例;
- ApplicationContext:繼承BeanFactory,有國際化、資源訪問、事件傳播等高級特性;
- FactoryBean:接口,存在復雜的初始化流程時使用;
- ObjectFactory:接口,用于延遲獲取對象,常作為參數傳遞。
Bean的作用域(生命周期和可見范圍)
- 單例
- 原型
- 請求
- 會話
- 應用
- webSocket會話
Bean的生命周期
- 實例化
- 屬性復制
- 初始化前
- 初始化
- 初始化后
- 使用中
- 銷毀
單例Bean不一定線程安全怎么辦?
- 使用無狀態的Bean
- 使用線程安全容器
- 使用同步機制
- ThreadLocal
- 將Scope更改為多例
初始化過程
- Bean定義信息的載入與解析
- Bean的實例化
- 屬性填充(依賴注入)
- 執行BeanPostProcessor接口
- Bean的初始化
- Spring Bean的生命周期完整
AOP
實現原理
JDK動態代理、CGLIB動態代理
AOP和AspectJ
- 實現機制:
- Spring AOP:基于動態代理和字節碼增強(在運行時通過代理對象或修改字節碼來織入切面邏輯),只能在運行時織如切面邏輯,對類的侵入性相對較小。
- AspectJ:是一個完整的AOP框架,提供了豐富的AOP語言支持。它可以通過編譯時織入(Compile - time Weaving)、類加載時織入(Load - time Weaving)等方式將切面邏輯織入到目標代碼中,功能更強大,能實現更細粒度的切面控制,但對項目的構建過程有一定影響,需要特定的編譯器或織入器支持。
- 功能范圍:
- Spring AOP:主要關注與Spring應用相關的切面需求,如對Spring Bean的方法進行切面增強,支持的連接點主要是方法調用。
- AspectJ:提供了更廣泛的連接點支持,除了方法調用,還包括字段訪問、構造函數調用等,能滿足更復雜的AOP需求。
- 使用難度:
- Spring AOP:與Spring框架緊密集成,使用Spring的配置或注解(如@Aspect、@Before等)就可以很方便地實現切面功能,對于熟悉Spring的開發者來說容易上手。
- AspectJ: 由于其功能豐富和實現方式的多樣性,學習曲線相對較陡,需要開發者對 AOP 概念和 AspectJ 語法有更深入的理解。
術語
- 切面
- 連接點
- 切入點
- 通知(前置通知、后置通知、返回通知、異常通知、環繞通知)
- 目標對象
- 代理
- 織入
事務
4種事務特性:原子性、一致性、隔離性、持久性
5種隔離機制:默認隔離級別、讀未提交、讀已提交、可重復讀、可串行化
7種傳播行為:required、supports、mandatory、requires_new、not_supported、never、nested
事務失效場景:
- 方法不是public修飾
- 自調用(內部方法調用)
- 未被Spring容器管理
- 異步被捕獲且未重新拋出
- 異步類型不匹配
- 數據源未配置事務管理器
- 多線程調用
注解
- 核心模式與組件定義:
- @Component:標記一個類為Spring組件。
- @Controller:標記一個類為 Spring MVC 控制器組件(是 @Component 的特化)。
- @Service:標記一個類為服務層業務邏輯組件(是 @Component 的特化)。
- @Repository:標記一個類為數據訪問層(DAO) 組件(是 @Component 的特化),自帶平臺特定的異常轉換功能。
- @Configuration + @Bean:用于基于Java的配置。@Configuration 標記一個類為配置類,其內部使用 @Bean 標注的方法會定義一個Bean,并交由Spring容器管理。
- 依賴注入與裝配:
- @Autowired:用于根據類型(byType)進行自動注入。
- @Qualifier:與 @Autowired 配合使用,當存在多個相同類型的Bean時,通過名稱(byName)來指定要注入的具體Bean。
- @Primary:設置一個Bean為首選項。當有多個相同類型的Bean且沒有指定 @Qualifier 時,優先注入帶有此注解的Bean。
- @Value:用于注入基本數據類型、SpEL表達式或配置文件中的屬性值(如 @Value(“${server.port}”))。
- Web MVC相關:
- RequestMapping、@GetMapping、@PostMapping:將HTTP請求映射到特定的控制器方法。
- @RequestBody:將HTTP請求的Body內容(通常是JSON/XML)綁定到方法的參數上。
- @ResponseBody:將方法的返回值直接綁定到HTTP響應體上(通常轉換為JSON/XML)。
- @PathVariable:將URL模板變量綁定到方法參數上(如/users/{id})。
- @RequestParam:將請求參數(URL查詢參數或表單數據)綁定到方法參數上。
- @ModelAttribute:將請求參數綁定到模型對象上,或用于在方法上提前準備模型數據。
- @RequestHeader:將請求頭(Header)的值綁定到方法參數上。
- @CookieValue:將Cookie的值綁定到方法參數上。
- @SessionAttribute:訪問預先存在于會話(Session)中的屬性。
- @ExceptionHandler:在控制器內部聲明一個方法來處理特定類型的異常。
- @ResponseStatus:標記方法或異常類,指定HTTP響應的狀態碼。
- 數據驗證:
- @Validated:Spring提供的注解,用于觸發校驗,支持分組校驗。
- @Valid:Java標準校驗注解,通常用于方法參數上觸發校驗。在Spring中,兩者常可互換,但@Validated功能更強大。
- Bean生命周期與作用域:
- @PostConstruct:標注一個方法,在Bean初始化完成后立即執行(類似于init-method)。
- @PreDestory:標注一個方法,在Bean被容器銷毀之前執行(類似于destroy-method)。
- @Scope:定義Bean的作用域(如:singleton、prototype、requeest、session等)。
- @Lazy:表示一個Bean是延遲初始化的,只有在第一次被使用時才會創建。
- 配置與條件化:
- @Profile:指定一個Bean或配置類只在特定的環境Profile激活時才會被注冊(如:“dev”、“prod”)。
- @Conditional:根據滿足某個特定條件(自定義或Spring內置條件,如 @ConditionalOnProperty)才注冊Bean,是更通用的條件化注解。
- @PropertySource:指定Spring加載指定的屬性文件(.properties 或 .yml)到環境(Environment)中。
- 高級功能:
- @Transactional:聲明式事務管理。
- @Cached、@CacheEvict、@CachePut:聲明式緩存,用于方法結果的緩存和清除。
- @Scheduled:用于聲明一個方法是定時任務,可以基于 cron、固定速率或固定延遲執行。
- @Async:聲明一個方法是異步執行的,調用此方法會立即返回,實際執行將提交給TaskExecutor。
- @EventListener:聲明一個方法為應用事件監聽器,用于監聽Spring容器內發布的Application。
Async
內部失效原因:Spring的AOP是基于代理實現的,而內部調用會繞過代理機制。
如何避免內部調用失效?
- 自我注入
- 使用ApplicationContext獲取代理對象
- 使用AopContext獲取代理對象
- 拆分為單獨的服務類
- 手動使用TaskExecutor
什么時候會失效?
- 未使用@EnableAsync注解
- 內部方法調用
- 方法非public
- 方法返回值錯誤
- 方法用static修飾了
- 方法用final修飾
- 業務類沒加@Service注解
- 自己new的對象
- Spring無法掃描異步類
攔截器和過濾器
過濾器和攔截器都是基于AOP思想實現的,用來解決項目中某一類問題的兩種工具。
攔截器
攔截器用于請求處理之前或之后執行的某些邏輯。攔截器可以用來實現日志記錄、權限檢查、性能監控等功能。
過濾器
比較
- 出身不同:過濾器來自Servlet,而攔截器來自于Spring框架。
- 觸發時機不同:請求進入容器 > 進入過濾器 > 進入 Servlet > 進入攔截器 > 執行控制器(Controller)。過濾器會先執行,然后才會執行攔截器,最后才會進入真正的要調用的方法。
- 實現不同:過濾器是基于方法回調實現的;攔截器是基于動態代理實現的。
- 支持的項目類型不同:過濾器要依賴 Servlet 容器,它只能用在 Web 項目中;而攔截器是 Spring 中的一個組件,因此攔截器既可以用在 Web 項目中,同時還可以用在 Application 或 Swing 程序中。
- 使用的場景不同:攔截器主要用來實現項目中的業務判斷的,過濾器通常是用來實現通用功能過濾的。
JPA和Hibernate
JPA是一套ORM的規范,定義了標準接口和注解
Hibernate是JPA規范的一種實現
Spring Data JPA 則是基于 JPA 規范的進一步抽象和封裝
參考
https://chuangshi.qq.com/read/29977156/9