深度理解spring——BeanFactory的實現

BeanFactory

  • Spring之BeanFactory
    • 什么是BeanFactory
    • ApplicationContext相對BeanFactory實現的功能性擴展
      • 1. MessageSource
      • 2. ResourcePatternResolver
      • 3. ApplicationEventPublisher
      • 4. EnvironmentCapable
      • 通用ApplicationContext實踐實現BeanFactory
      • BeanFactory后處理器排序讓誰優先執行
      • 第一種實現通過xml等方式實現的bean注入原理
        • 第二種基于磁盤路徑下 xml 格式的配置文件來創建
        • 第三種較為經典的容器,基于java配置類來創建
        • 第四種較為經典的容器,基于java配置類來創建,并且還可以用于web環境

Spring之BeanFactory

什么是BeanFactory

BeanFactory是SpringApplication類的父類接口
BeanFactory才是Spring的核心容器,主要的SpringApplication類都組合了他的功能。
通過Ctrl+alt+u可以看到
在這里插入圖片描述
可以從圖片中看到SpringApplication是繼承了BeanFactory接口對BeanFactory進行了功能性的擴展。
比如SpringApplication獲取一個bean的對象

       run.getBean(BreadRollMallServer.class);

他實際上是通過組合了BeanFactory實現找個獲取對象的功能,可以看出來SpringApplication是間接的調用了BeanFactory的功能
在這里插入圖片描述

ApplicationContext相對BeanFactory實現的功能性擴展

在這里插入圖片描述

1. MessageSource

MessageSource 是 Spring 框架里用于消息解析與國際化的核心接口。借助它,你能夠依據不同的語言環境獲取對應的文本消息,從而實現國際化支持。像錯誤消息、提示信息這類文本內容,就可以通過 MessageSource 進行管理。

2. ResourcePatternResolver

ResourcePatternResolver 接口可用來解析資源路徑,并且支持使用通配符來匹配多個資源。它是 ResourceLoader 的擴展,能夠依據給定的資源路徑模式查找多個資源。在加載配置文件、靜態資源等場景中會經常用到。

3. ApplicationEventPublisher

ApplicationEventPublisher 接口提供了發布應用事件的功能。在 Spring 應用里,事件機制是一種重要的設計模式,允許組件之間以松耦合的方式進行通信。通過 ApplicationEventPublisher,你可以發布自定義的應用事件,其他組件可以監聽這些事件并做出響應。

應用場景:用戶注冊時候的發短信發郵件。

4. EnvironmentCapable

EnvironmentCapable 接口表明一個對象具備獲取 Environment 對象的能力。Environment 對象封裝了應用程序運行時的環境信息,包含系統屬性、環境變量、配置文件屬性等。借助 Environment,你可以方便地獲取和管理這些屬性。

通用ApplicationContext實踐實現BeanFactory

public class TestBeanFactory {public static void main(String[] args) {DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();// bean 的定義(class(類型), scope(單例or多例), 初始化方法, 銷毀方法)// BeanDefinitionBuilder..xxx.xxx.xxx.getBeanDefinition()AbstractBeanDefinition beanDefinition =BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();//(beanName,xxx)將bean注冊到bean工廠中beanFactory.registerBeanDefinition("config", beanDefinition);// 【重點】給 BeanFactory 添加一些常用的后處理器(對BeanFactory的擴展) //將后處理添加到bean工廠AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);// BeanFactory 后處理器主要功能,補充了一些 bean 定義// beanFactory.getBeansOfType 根據類型獲取多個bean//BeanFactoryPostProcessor.class拿到bean工廠的所有后處理器,對bean工廠做出擴展就可以解析@bean注解等。beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {//拿到bean工廠的所有后處理器并且執行beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);//執行BeanFactory后置處理器});// 添加 BeanPostProcessor  也就是添加bean的后處理器//bean后處理器 針對bean的生命周期各個階段進行擴展,例如@Autowire @ResousebeanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);for (String name : beanFactory.getBeanDefinitionNames()) {System.out.println(name);}}@Configurationstatic class Config {@Beanpublic Bean1 bean1() {return new Bean1();}@Beanpublic Bean2 bean2() {return new Bean2();}}static class Bean1 {private static final Logger log = LoggerFactory.getLogger(Bean1.class);@Autowiredprivate Bean2 bean2;}static class Bean2 {private static final Logger log = LoggerFactory.getLogger(Bean2.class);}
}

通過這個案例,你可以看到如何使用 DefaultListableBeanFactory 創建和管理 Bean,以及如何使用后置處理器在 Bean 的生命周期中執行自定義邏輯。
區別對比

  1. 作用時機
    BeanFactoryPostProcessor:在 BeanFactory 完成 Bean 定義的加載之后,但在 Bean 實例化之前執行。也就是說,它處理的是 Bean 的定義信息,而不是 Bean 實例。
    BeanPostProcessor:在 Bean 實例化之后,初始化前后執行。它作用于已經創建好的 Bean 實例。
  2. 作用對象
    BeanFactoryPostProcessor:作用于 BeanFactory 本身,主要用于修改 BeanFactory 中 Bean 的定義信息,例如修改 Bean 的屬性值、作用域等。
    BeanPostProcessor:作用于具體的 Bean 實例,允許開發者在 Bean 初始化前后對其進行定制化處理。
  3. 功能側重點
    BeanFactoryPostProcessor:側重于對 Bean 定義的全局修改和擴展,例如動態添加或修改 Bean 定義,調整 Bean 的配置等。
    BeanPostProcessor:側重于對 Bean 實例的個性化處理,例如對 Bean 進行增強、驗證、日志記錄等。

總結:
1.bean工廠不會主動調用beanFactory后處理器
2.bean不會主動添加后處理器
3.不會主動初始化單例
4.不會解析BeanFactory

BeanFactory后處理器排序讓誰優先執行

在這里插入圖片描述

第一種實現通過xml等方式實現的bean注入原理

通過xml注入bean容器

  // ??1.最為經典的容器,基于classpath 下 xml 格式的配置文件來創建public void testClassPathXmlApplicationContext() {ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring_bean.xml");for (String name : context.getBeanDefinitionNames()) {System.out.println(name);}System.out.println(context.getBean(Bean2.class).getBean1());}
第二種基于磁盤路徑下 xml 格式的配置文件來創建
        //基于磁盤路徑下 xml 格式的配置文件來創建DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();System.out.println("讀取之前");for (String name : beanFactory.getBeanDefinitionNames()) {System.out.println(name);}System.out.println("讀取之后");XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);;reader.loadBeanDefinitions(new FileSystemResource("src\\main\\resources\\spring_bean.xml"));for (String name : beanFactory.getBeanDefinitionNames()) {System.out.println(name);}
第三種較為經典的容器,基于java配置類來創建

較為經典的容器,基于java配置類來創建,通過這個配置類創建會幫我們創建后處理器了來解析@Bean注解

   // ??3.較為經典的容器,基于java配置類來創建public void testAnnotationConfigApplicationContext() {// 會自動加上5個后處理器// org.springframework.context.annotation.internalConfigurationAnnotationProcessor// org.springframework.context.annotation.internalAutowiredAnnotationProcessor// org.springframework.context.annotation.internalCommonAnnotationProcessor// org.springframework.context.event.internalEventListenerProcessor// org.springframework.context.event.internalEventListenerFactoryAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);for (String name : context.getBeanDefinitionNames()) {System.out.println(name);}System.out.println(context.getBean(Bean2.class).getBean1());}
// 單元測試的過程中如果要解析一些Spring注解,比如@Configuration的時候不要把相關類定義到寫單元測試類的內部類,會讀取不到
@Configuration
class Config {@Beanpublic Bean1 bean1() {return new Bean1();}@Beanpublic Bean2 bean2(Bean1 bean1) {Bean2 bean2 = new Bean2();bean2.setBean1(bean1);return bean2;}
}class Bean1 {}class Bean2 {private Bean1 bean1;public Bean1 getBean1() {return bean1;}public void setBean1(Bean1 bean1) {this.bean1 = bean1;}
}
第四種較為經典的容器,基于java配置類來創建,并且還可以用于web環境
// 模擬了 springboot web項目內嵌Tomcat的工作原理public void testAnnotationConfigServletWebServerApplicationContext() throws IOException {AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);// 防止程序終止System.in.read();}@Configuration
class WebConfig {@Bean// 1. WebServer工廠public ServletWebServerFactory servletWebServerFactory() {return new TomcatServletWebServerFactory();}@Bean// 2. web項目必備的DispatcherServletpublic DispatcherServlet dispatcherServlet() {return new DispatcherServlet();}@Bean// 3. 將DispatcherServlet注冊到WebServer上public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet) {return new DispatcherServletRegistrationBean(dispatcherServlet, "/");}@Bean("/hello")public Controller controller1() {return (request, response) -> {response.getWriter().println("hello");return null;};}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/902727.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/902727.shtml
英文地址,請注明出處:http://en.pswp.cn/news/902727.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

跑MPS產生委外采購申請(成品)

問題:跑MPS產生委外采購申請(成品),更改BOM和跑MRP,但物料需求清單中無新增物料復合膜的需求。截圖如下: 解決方法:更改委外采購申請的批準日期為BOM的生效日和重新展開bom。 重新展開后&#x…

“在中國,為中國” 英飛凌汽車業務正式發布中國本土化戰略

3月28日,以“夯實電動化,推進智能化,實現高質量發展”為主題的2025中國電動汽車百人會論壇在北京舉辦。眾多中外機構與行業上下游嘉賓就全球及中國汽車電動化的發展現狀、面臨的挑戰與機遇,以及在技術創新、市場布局、供應鏈協同等…

優雅實現網頁彈窗提示功能:JavaScript與CSS完美結合

在現代Web開發中,彈窗提示是提升用戶體驗的重要元素之一。本文將深入探討如何實現一個優雅、可復用的彈窗提示系統,避免常見問題如重復觸發、樣式混亂等。 核心代碼解析 // 控制彈窗是否可以顯示的標志 let alertStatus true;// 顯示提示信息 functio…

YOLOv11改進-雙Backbone架構:利用雙backbone提高yolo11目標檢測的精度

一、引言:為什么我們需要雙Backbone? 在目標檢測任務中,YOLO系列模型因其高效的端到端檢測能力而備受青睞。然而,傳統YOLO模型大多采用單一Backbone結構,即利用一個卷積神經網絡(CNN)作為特征提…

用 PyQt5 和 asyncio 打造接口并發測試 GUI 工具

接口并發測試是測試工程師日常工作中的重要一環,而一個直觀的 GUI 工具能有效提升工作效率和體驗。本篇文章將帶你用 PyQt5 和 asyncio 從零實現一個美觀且功能實用的接口并發測試工具。 我們將實現以下功能: 請求方法選擇器 添加了一個下拉框 QComboBo…

理解npm的工作原理:優化你的項目依賴管理流程

目錄 什么是npm npm核心功能 npm 常用指令及其作用 執行npm i 發生了什么? 1. 解析命令與參數 2. 檢查依賴文件 3. 依賴版本解析與樹構建 4. 緩存檢查與包下載 5. 解壓包到 node_modules 6. 更新 package-lock.json 7. 處理特殊依賴類型 8. 執行生命周期腳本 9. …

React Native 安卓端 android Image 播放gif webp 動態圖

React Native 安卓端 android Image 播放gif webp 動態圖 RN項目是0.78.2 React是19.0 基本介紹 Image 是 React Native 中用于顯示各種類型圖片的核心組件,支持顯示網絡圖片、靜態資源、本地圖片以及 base64 編碼的圖片。在 Android 端,Image 組件還可…

實時數字人——DH_LIVE

前兩天親手搭建了實時對話數字人VideoChat,今天來搭建下DH_LIVE。 DH_LIVE一個實時數字人解決方案,從輸入文字到數字人對口型說話用時2-3秒。 今天就來實際操作下dh_live的搭建過程。 首先貼上git地址:https://github.com/kleinlee/DH_liv…

AOSP CachedAppOptimizer 凍結方案

背景 Android 一直面臨一個核心難題:如何優化進程對有限系統資源(如 CPU、電量)的使用,同時保證用戶體驗。 當進程進入后臺后,它們雖不再貢獻用戶體驗,卻仍可能消耗資源。傳統的殺后臺方案雖然節省資源&a…

實體店的小程序轉型之路:擁抱新零售的密碼-中小企實戰運營和營銷工作室博客

實體店的小程序轉型之路:擁抱新零售的密碼-中小企實戰運營和營銷工作室博客 在當今數字化浪潮的沖擊下,實體店面臨著前所未有的挑戰,但小程序的出現為實體店轉型新零售帶來了新的曙光。先來看一組驚人的數據,據相關統計&#xff…

Java求職面試:從Spring Boot到微服務的全面考核

Java求職面試實錄:從Spring Boot到微服務的全面考核 第一輪:基礎技術的考察 場景: 趙大寶走進了一家互聯網大廠的面試間,面試官嚴肅地看著他。 面試官: 趙大寶,你好。我們先從簡單的開始。請你解釋一下J…

記錄一個坑關于STM32 ARM Compiler Version

在用 Keil 進行 STM32 開發的時候,一開始下載,下載的 ARM 編譯器是 Version6,他就不兼容老的代碼,就很抽象。 所以必須要更換編譯器。 可以去官網下載編譯器 Downloads - Arm Developer ,也可以自己找資源哈&#xff…

PCIe體系結構學習入門——PCI總線概述(二)PCI總線的橋和配置

這里寫目錄標題 序言存儲器域和 PCI 總線域HOST 主橋PCI 橋和 PCI 設備配置空間PCI 橋PCI 設備配置空間PCI 總線的配置非透明 PCI 橋序言 接續前章內容,本章繼續講述 PCI 總線概述的第二部分——PCI 總線的橋和配置。 如果需要進一步了解前一章節內容,可以訪問:PCIe體系結構…

潯川代碼編輯器v2.0(測試版)更新公告

潯川代碼編輯器v2.0(測試版)更新公告 發布日期:** 2023年4月30日 我們很高興地宣布潯川代碼編輯器v2.0測試版即將上線!本次更新帶來了多項功能改進和問題修復,旨在為用戶提供更穩定、更強大的編程體驗。 主要更新內容 1. **Bug修復與穩定性提…

微信小程序 tabbar底部導航欄

官方文檔:https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html#tabBar 一、常規菜單格式 在app.json 文件中配置,其他關鍵點詳見官方文檔,后續更新不規則圖標的寫法

Spring 中@Autowired,@Resource,@Inject 注解實現原理

使用案例 前置條件: 現在有一個 Vehicle 接口,它有兩個實現類 Bus 和 Car ,現在還有一個類 VehicleService 需要注入一個 Vehicle 類型的 Bean: public interface Vehicle {}Component public class Car implements Vehicle {}C…

【Rust結構體】Rust結構體詳解:從基礎到高級應用

?? 歡迎大家來到景天科技苑?? 🎈🎈 養成好習慣,先贊后看哦~🎈🎈 🏆 作者簡介:景天科技苑 🏆《頭銜》:大廠架構師,華為云開發者社區專家博主,…

《LightLLM:開啟大語言模型推理新時代》

《LightLLM:開啟大語言模型推理新時代》 大語言模型推理的困境與挑戰 在當今人工智能飛速發展的時代,大語言模型(LLMs)無疑是最為耀眼的明星技術之一。從 OpenAI 的 GPT 系列到谷歌的 BERT,再到國內如百度文心一言、阿里通義千問等,大語言模型以其強大的語言理解和生成能…

【Python Web開發】02-Socket網絡編程02

文章目錄 1. 服務器端1.1 socket.socket()1.2 socket.bind()1.3 socket.listen()1.4 socket.accept()1.5 socket.recv()1.6 socket.send() 和 socket.sendall()1.7 socket.close() 2. 客戶端2.1 socket.socket()2.2 socket.connect()2.3 socket.send() 和 socket.sendall()2.4 …

Flutter 在全新 Platform 和 UI 線程合并后,出現了什么大坑和變化?

Flutter 在全新 Platform 和 UI 線程合并后,出現了什么大坑和變化? 在兩個月前,我們就聊過 3.29 上《Platform 和 UI 線程合并》的具體原因和實現方式,而事實上 Platform 和 UI 線程合并,確實為后續原生語言和 Dart 的…