日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring IOC 组件概述

發布時間:2025/3/15 javascript 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring IOC 组件概述 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
  • IOC 概述
    IOC: Inversion of Control(控制反轉), 這里其實指的是: 將程序中需要使用的 POJOs, 丟入到容器中, 解析成統一的 BeanDefinition(主要基于XML的 GenericBeanDefinition/RootBeanDefinition 與 通過 注解生成的 ScannedGenericBeanDefinition), 而 Bean 依賴的信息都在XML中描述(或通過注解描述), 容器則負責 Bean 的統一生成(本來Bean的創建/銷毀是由我們開發人員控制的), 因此造成了 Bean 的創建/銷毀由Bean容器控制的反轉現象!(通過下圖理解一下)
  • 圖中角色:

  • 如上圖 Spring IOC 容器使用了 Configuration Metadata, Configuration Metadata 告知 Spring容器如何去實例化, 配置和裝配對應的對象
  • Configuration Metadata(及 BeanDefinition)現在主要由解析XML.Properties 或通過掃描指定目錄下帶有特定
  • IOC 主要組件 BeanDefinition 的屬性
    先看一下 BeanDefinition 主要屬性
  • // Bean 的Class 對象 private volatile Object beanClass;// bean 的作用范圍, 對應 bean 屬性 scope (常見的就是單例/原型) private String scope = SCOPE_DEFAULT;// 是否是抽象, 來自 bean 屬性的 abstract(抽象的類是不能直接生成對象) private boolean abstractFlag = false;// 是否延遲加載, 對應 bean 屬性 lazy-init (值是否在使用 Bean的時候才正真的創建 Bean) private boolean lazyInit = false;// 自動注入模式, 對應 bean 屬性 autowire (這個屬性主要指 XML 描述的 beanDefinition, 在生成bean的對吼階段, 獲取容器中的對象, 自動裝配在 BeanDefinition 對應的 Field 上) private int autowireMode = AUTOWIRE_NO;// 依賴檢查, Spring 3.0 后 棄用這個屬性 private int dependencyCheck = DEPENDENCY_CHECK_NONE;// 用來表示一個 bean 的實例化依靠另一個 bean 先實例化(PS: 這個很少使用了) private String[] dependsOn;/*** autowire-candidate 屬性設置為 false, * 這樣容器在查找自動裝配對象時* 將不考慮該 bean, 即它不會被考慮作為其他 bean * 自動裝配的候選者, 但是該 bean * 本身還是可以使用自動裝配來注入其他的 bean*/ private boolean autowireCandidate = true;// 自動裝配時當出現多個 bean 候選者時, 將作為首候選者 (PS: 使用比較少) private boolean primary = false;// 用于記錄 Qualifier, 對應子元素 qualifier(當使用 @Autowired 時, 有多個候選Bean 時, 就通過這個Qualifier 來進行區分) private final Map<String, AutowireCandidateQualifier> qualifiers =new LinkedHashMap<String, AutowireCandidateQualifier>(0);// 允許訪問非公開的構造器和方法, 程序設置 (PS: 用得比較少) private boolean nonPublicAccessAllowed = true;/*** 是否以一種寬松的模式解析構造函數, 默認 true* 如果是 false, 則在如下情況* interface ITest()* class ITestImpl implement ITest();* class Main {* Main(ITest i) {}* Main(ITestImpl i) {}* }* 拋出異常, 因為 Spring 無法準確確定哪個構造函數* 程序設置** lenient 寬大, 仁慈*/ private boolean lenientConstructorResolution = true;/*** 對應 bean 屬性 factory-bean 用法 (PS: 這里涉及 FactoryBean 這個概念, 這個類主要是解決: 創建一個類, 但創建這個類的過程比較長/條件比較多, 這時候就使用同一的抽象工廠模式(FactoryBean對象) 來創建對象)* <bean id="instanceFactoryBean" class="example.chapter3.InstanceFactoryBean />* <bean id="currentTime" factory-bean="instanceFactoryBean" factory-method="createTime" />*/ private String factoryBeanName;// 對應 bean 屬性 factory-method private String factoryMethodName;// 記錄構造函數注入屬性, 對應 bean 屬性 constructor-arg private ConstructorArgumentValues constructorArgumentValues;// 普通屬性集合 (在XML 中定義Bean的信息時, 通常propertyValues里面有很多依賴信息) private MutablePropertyValues propertyValues;// 方法重寫的持有者, 記錄 lookup-method, replaced-method 元素(PS: 與此對應有注解Loopup, 但運用的比較少了) private MethodOverrides methodOverrides = new MethodOverrides();// 初始化方法, 對應 bean 屬性 init-method (PS: 通過 實現InitializingBean 接口, 可以達到同樣效果) private String initMethodName;// 銷毀方法, 對應 bean 屬性 destory-method (PS: 與之對應的是 DisposableBean, 一幫都是在這類方法中完成資源釋放之類的操作) private String destroyMethodName;// 是否執行 init-method, 程序設置 (默認是 true) private boolean enforceInitMethod = true;// 是否執行 destory-method, 程序設置 (默認是 true) private boolean enforceDestroyMethod = true;// 是否是用戶定義的而不是應用程序本身定義的, 創建 AOP 部分組件時為 true(見 ConfigBeanDefinitionbeanParser.parseAdvice 方法) private boolean synthetic = false;/*** 定義這個 bean 的應用, APPLICATION: 用戶, INFRASTRUCTURE(infrastructure 基礎設施): 內部使用, 與用戶無關, SUPPORT: 某些復雜配置的一部分程序設置, 一般都是 BeanDefinition.ROLE_APPLICATION;*/ private int role = BeanDefinition.ROLE_APPLICATION;// bean 的描述信息 private String description;// 這個 bean 定義的資源 (其實就是 A.class 這個文件) private Resource resource;

    PS: 屬性好多, 一直其實上面屬性中相對重要的有一下幾個

    • 2.1 class(該實例化的 Bean), name(bean的命名)

    • 2.2 scope(定義Bean的生命周期)

    • 2.3 constructor arguments(Bean構造函數依賴注入的屬性)

    • 2.4 properties(Bean依賴注入的屬性, 這里的 properties 主要還是指XML或properties里面描述的信息)

    • 2.5 autowiring mode(是否自動裝配, 若是的話, 則容器會在整個容器中尋找所有符合條件的 Field)

    • 2.6 lazy-initialization mode (是否 lazy 生成Bean, 指是否在正真需要使用 Bean時才會創建bean, 但現在運用中一般都是使用 ApplicationContext 的子類, 這個類會在 refresh()
      方法里面中調用 finishBeanFactoryInitialization(), 然后再調用
      preInstantiateSingletons 來實例化容器中的所有類),

    • 2.7 initialization method
      (Spring 容器中 bean 的初始化方法, 這個完全可以通過實現接口 InitializingBean 來實現)

    • 2.8 destruction method (Spring 容器中 bean 的銷毀方法, 這個也完全可以通過實現接口 DisposableBean 來實現)

    • PS: 這個有個漏掉的點: 在Spring 創建 Bean的過程中, 容器里面的 BeanFactoryPostProcessor
      可以對Bean的元數據進行一定的修改

  • IOC 主要組件 BeanDefinition 的分類
    BeanDefinition 其實是根據 BeanDefinition 的收集策略來進行分類的, 主要分成下面:
  • GenericBeanDefinition: 一個標準的 BeanDefinition, 通過XML 讀取Bean的描述信息組裝的BeanDefinition一般都是GenericBeanDefinition, 后續的beanDefinition 都是在這個類的基礎上進行擴展
  • ScanedGenericBeanDefinition: 這個類擴展于 GenericBeanDefinition, 底層是通過 ASM 的ClassReader 來獲取對應注解 Annotation 相關的元數據
  • AnnotatedGenericBeanDefinition: 這個 BeanDefinition 與上面的ScanedGenericBeanDefinition 很相似, 都具有 bean上注解的描述信息,AnnotatedGenericBeanDefinition 這個類主要是在使用AnnotationConfigApplicationContext創建容器時, 通過 AnnotationBeanDefinitionReader 來獲取對應 BeanDefinition 時創建的
  • IOC 主要組件 BeanDefinitionReader 概述
  • 先看一下接口BeanDefinitionReader 的主要方法

    // beanDefinition 的讀取者 // 這里有個注意點, BeanDefinition 的讀取器不一定非要實現BeanDefinitionReader接口, 其實這里指的就是 AnnotatedBeanDefinitionReader 與 ClassPathBeanDefinitionScanner public interface BeanDefinitionReader {// 這里的 BeanDefinitionRegistry 其實就是 beanFactory 的注冊接口, BeanDefinition 通過這個接口注入到 BeanFactory 看一下 BeanDefinitionRegistry 的實現類就知道了BeanDefinitionRegistry getRegistry();// ResourceLoader 代表的是 BeanDefinitionReader 需要讀取的是 描述BeanDefinition的資源文件加載器, 以前 BeanFactory 與 ResourceLoader 是分離開的兩個組件, 后來出現了 ApplicationContext, 將 beanFactory 與 ResourceLoader 結合到一個類中ResourceLoader getResourceLoader();// 加載類的 ClassLoaderClassLoader getBeanClassLoader();// bean 的命名生成器BeanNameGenerator getBeanNameGenerator();// 加載指定目錄Resource下 BeanDefinition 的方法int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;// 加載多個指定目錄Resource下 BeanDefinition 的方法int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;// 加載指定目錄Resource下 BeanDefinition 的方法int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;// 加載多個指定目錄Resource下 BeanDefinition 的方法int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException; }

    上面方法定義了獲取 BeanDefinition的主要生成策略, 但其中有個重要的點, 就是 BeanDefinition 的讀取器不一定非要實現 BeanDefinitionReader 接口, 比如 AnnotatedBeanDefinitionReader(直接注入帶注解的bean) 與 ClassPathBeanDefinitionScanner(掃描指定目錄下面帶注解的Bean)

  • IOC 主要組件 BeanDefinitionReader 分類
    BeanDefinitionReader 首先是通過一個抽象類 AbstractBeanDefinitionReader 來定義了加載 beanDefinition 的模板方法(模板模式), 接下來根據在不同文件(XML/Properties)中定義Bean描述信息來實現不同類別的 BeanDefinitionReader(策略模式)
  • AbstractBeanDefinitionReader: 實現 beanDefinitionReader 接口的抽象類, 主要定義了加載類的主邏輯, 后續的類依據不同存儲文件不同格式, 有不同的具體實現類
  • PropertiesBeanDefinitionReader: 讀取 properties 文件的 beanDefinitionReader, 這個類相對簡單, 但是沒有下面的 XMLBeanDefinitionReader 擴展性那么好
  • GroovyBeanDefinitionReader: 這個類是基于 XMLBeanDefinitionReader 實現的 BeanDefinitionReader
  • XmlBeanDefinitionReader: 最常見的 BeanDefinitionReader, 也是相對擴展性最好的 Reader(PS: 它的擴展性主要體現在自定義命名空間, 比如 <mvc...>, <aop...>, <tx...>, 或者dubbo擴展的 <dubbo....>)
  • AnnotatedBeanDefinitionReader: 雖然沒有實現 BeanDefinitionReader 接口, 但是它其實還是個 BeanDefinitionReader, 主要是當使用基于注解驅動的
    AnnotationConfigApplicationContext 時使用的
  • ClassPathBeanBeanDefinitionScanner: 這個類也沒有實現BeanDefinitionReader , 但是它非常強大, 知道指定一個掃描的目錄, 就會將符合條件的Bean生成 ScanedGenericBeanDefinition 對象,注入到容器中(PS: 當Spring的XML文件中定義了 context:component-scan 也會創建這個類,并且通過這個類掃描指定目錄項目的類, 并registry 到 BeanFactory 中) 上面額幾種beanDefinitionReader中, XmlBeanDefinitionReader,
    AnnotatedBeanDefinitionReader, ClassPathBeanBeanDefinitionScanner
    是比較重要的, 也是最常見的
  • IOC 主要組件 Resource 概述
    Resource: Spring 里面對資源進行封裝的統一抽象接口, 里面定義了一些通用的方法, 詳情如下:
  • // Spring 中資源的統一抽象接口 public interface Resource extends InputStreamSource {// 返回的資源是否存在boolean exists();// 返回的資源是否可讀boolean isReadable();// 返回這個資源是否有已打開流的處理, 若果是 true, 則此 InputStream 就不能被多次讀取, 而且只能被讀取和關閉以免資源泄露boolean isOpen();// 轉換 Resource 到 URLURL getURL() throws IOException;// 轉換 Resource 到FileFile getFile() throws IOException;// 返回資源內容的長度long contentLength() throws IOException;// 資源上次修改時間long lastModified() throws IOException;// 創建資源相對于這個資源Resource createRelative(String relativePath) throws IOException;// 對的這個資源的名字String getFilename();// 返回資源的描述, 用于錯誤處理中打印的信息String getDescription(); }

    上面是資源抽象的統一接口, 而針對資源獲取的不同方式, 對應的有相應的子類(PS: AbstractResource 是其對應的抽閑子類, 其間定義了一些抽象的方法, 所有的子類都是從這個類派生出來)

  • IOC 主要組件 Resource 類別
  • 在 Spring 中針對獲取資源的不同渠道, 創建了相應的 Resource(主要是依據 路徑的格式不同, 來創建不同類別的 Resource), 其中有我們進行開發中常用的一些類, 如下:

  • FileSystemResource: 比如使用容器 FileSystemXmlApplicationContext時, 配置的 XML 資源都會被封裝成FileSystemResource
  • ServletContextResource: 若是用 XmlWebApplicationContext 系列的 ApplicationContext 容器時, 一般都是生成這個(PS: 這時是以 "/" 開頭)
  • ClassPathResource: 當使用 ClassPathXmlApplicationContext 時, 最終將資源包裝成 ClassPathResource(則對應的資源將通過 ClassLoader 進行加載)(PS: 這時是以 "/" 或"classpath:"開頭, 若不是的話, 則封裝成 URLResource)
  • PS: 在上面創建 Resource時, 若遇到 Classpath*: 開頭時, 則將通過 PathMatchingResourcePatternResolver 來進行獲取對應資源, 這時又會判斷是否路徑中含有 “*/?” 這種字符串, 則獲取能正則匹配成功的所有文件;

    補充: classpath*: 代表的是獲取當前ClassLoader對應的 URLClassPath下面的所有包中匹配的資源(包括父ClassLoader, 詳情見PathMatchingResourcePatternResolver.getResources(String locationPattern) ); 而 classpath 則是通過Class.getResourceAsStream(String path) 來獲取一個數據流, 對滴就一個文件(詳情見 ClassPathResource.getInputStream())

  • IOC 主要組件 ResourceLoader 概述
    ResourcceLoader 中定義了獲取Spring中統一資源的方法, 它將根據路徑的前綴來生成對應的 Resource, 其中最通用的就是下面這幾種:
  • DefaultResourceLoader: 這個類是 AbstractApplicationContext 的超類, 其間定義了獲取 Resourcce的默認方法 getResource(String location); 若路徑以"/"開頭, 則交由子類創建對應的
    Resource(根據不同的子類類別創建不同的 Resource, 如
    FileSystemXmlApplicationContext的FileSystemResource,
    GenericWebApplicationContext 的 ServletContextResource,
    ClassPathXmlWebApplicationContext的ClassPathResource), 若路徑以
    “classpath:” 開頭, 則創建 ClassPathResource, 若不是以上兩種情況, 則直接創建 UrlResource
  • PathMatchingResourcePatternResolver: 這個類是在創建 AbstractApplicationContext 時默認創建的 ResourceResolver, 當遇到的路徑是以
    "classpath*: " 開頭是就通過這個類來獲取 ClassLoader的classpath下面的所有 jar
    中的符合條件的XML資源(PS: PathMatchingResourcePatternResolver是一個非常重要的類,
    而且它獲取資源的方式非常直接借鑒)
  • IOC 主要組件 BeanDefinitionDocumentReader
    這個類存在的意義主要是封裝成 XML文件為 Document, 并且根據每個節點的命名空間獲取對應的 Namespacehandler 來進行處理解析對應的節點; 其默認實現就是 DefaultBeanDefinitionDocumentReader; 對于普通的命名空間 “http://www.springframework.org/schema/beans”, 則直接用 BeanDefinitionParserDelegate的parseBeanDefinitionElement來進行解析; 若遇到其他命名空間的, 則通過NamespaceHandlerResolver 來獲取對應的 NamespaceHandler 來進行解析
    (PS: NamespaceHandler 也是通過META-INF/Spring.handlers 下面定義的命名空間對應的Namespacehandler, 并通過反射來進行創建, 具體看 DefaultNamespacehandlerResolver 的gethandlerMappings )

  • IOC 主要組件 NamespaceHandler
    Spring解析XML 時, 主要依據命名空間來選擇對應的 NamespaceHandler 來進行解析

  • http://www.springframework.org/schema/beans 對應 默認的解析類 BeanDefinitionParserDelegate
  • 當遇到其他命名空間時, 則通過 DefaultNamespaceHandlerResolver.resolve(namespaceUri) 來獲取對應的
    NamespaceHandler 來進行解析(比如遇到 <mvc…>, <aop…>, <tx…>, 或者 dubbo
    中的)
  • DefaultNamespaceHandlerResolver 通過獲取所有 “META-INF/spring.handlers” 里面定義的 Namespacehandler, 并找到namespace與之對應的進行解析

  • IOC 主要組件 BeanFactoryPostProcessor
    BeanFactoryPostProcessor: 對這個名詞進行分割; BeanFactoryPostProcessor = BeanFactory(bean工廠) + Post(后) + Processor(處理器); 這樣就好理解了!
  • public interface BeanFactoryPostProcessor {// 這個方法在 BeanFactory 加載好所有的 Bean 信息到容器后, 實例化任何Bean實例之前(Bean在容器中有實例化(Instantiation)與初始化(Initialization)的差別, 這點很重要)void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException; }

    對于這個類, 最常見的就是用于修改 Bean 的屬性, 比如一開始在對應屬性上面設置 “${}” 設置這樣的占位符, 然后通過對應類進行賦值

  • BeanFactoryPostProcessor: 定義了方法執行的入口(在加載所有Bean信息到容器之后)
  • PropertiesLoaderSupport: Properties加載/解析的方式方法
  • PropertyResourceConfigurer: 繼承PropertiesLoaderSupport,
    實現BeanFactoryPostProcessor接口, 其中定義執行方法的主邏輯, 并留下模板方法
    processorProperties(), 留給子類去實現
  • PropertyOverrideConfigurer: 這個類主要在
    properties 文件里面寫入 beanName.fieldname=fieldvalue 這樣的鍵值對來進行解析數據
  • PropertySourcesPlaceholderConfigurer/PropertyPlaceholderConfigurer:
    這兩個類都是繼承PropertyResourceConfigurer, 但與PropertyOverrideConfigurer不同的是,
    這兩個類都是通過"${}" 這種占位符號來確定哪個數據需要替換成 Properties 里面的數據, 其中還涉及到了非常有效的工具類
    PlaceholderResolver(這個類是來獲取對應數據中所有的 ${} 中的數據, 其中涉及到遞歸獲取,
    這種獲取的方式其實很值得借鑒), 當然還有我們熟悉的設計模式 --> 觀察者模式, 通過 BeanDefinition 的觀察者
    BeanDefinitionVisitor 來進行 visitor 每一個
    BeanDefinition中的屬性(見BeanDefinitionVisitor)
  • IOC 主要組件 BeanPostProcessor
    BeanPostProcessor 接口是Spring IOC 中擴展機制的提現, 自己可以在BeanPostProcessor的回調方法中實現 "實例化邏輯, 依賴分析"等;
    它具有以下特定:
  • 可以在容器中注入多個 BeanPostProcessor, 并且通過 Ordered接口來控制 BeanPostProcessor實現的次序;
  • BeanPostProcessor 的 postProcessbeforeInitialization方法作用在 bean 的初始化方法(PS: 這里的初始化方法主要是通過xml中配置的, 或者實現 InitializingBean接口而具有的afterPropertiesSet)前面調用, 作用在 Bean 實例化, 并且設置好 XML 中配置的依賴熟悉之后調用(PS:其中包括InstantiationAwareBeanPostProcessr的postProcessPropertyValues 之后
    —> postProcessPropertyValues 主要是將 bean中被 @Autowired,@Resource, @PersistenceContext, @Required 注解修飾屬性注入對應的值);而在Spring容器自己提供的幾個 BeanPostProcesser的實現類中, 可以看到在 ApplicationContextAwareProcessor 中完成了一下Aware 接口的喚醒
  • BeanPostProcessor 的 postProcessAfterInitialization方法主要作用在 Bean的初始化方法之后執行(PS: 這時的bean已經實例化,并且進行類依賴注入+Aware接口的喚醒), 對于這個接口,最常見的就是通過這個接口實現對 Bean 的 AOP(PS: 其中涉及到一個 IOC 容器中配置多個 AbstractAutoProxyCreator 的情況, 而其內部通過advisedBeans來判斷 Bean 是否已經被 動態代理了);在自動AOP中, 主要有基于命名空間的 AspectJAwareAdvisorAutoProxyCreator 與 基于 @AspectJ注解風格的 AnnotationAwareAspectJAutoProxyCreator
    (PS: 針對這兩個類, 在介紹AOP中會詳細解析)
  • InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation: Spring中 bean 的實例化前置處理器, 當系統中配置 customTargetSourceCreators 時, 將通過特定的 TargetSource 來對 Bean 進行動態代理,若類已經被動態代理了, 則相應的也會執行 BeanPostProcessor.postProcessAfterInitialization方法(PS: postProcessAfterInitialization 里面可能有些其他的邏輯需要執行)
  • InstantiationAwareBeanPostProcessor 的 postProcessAfterInstantion: bean 實例的后置方法, 其主要是控制是否需要將 xml 中配置的 Spring 屬性進行注入 + InstantiationAwareBeanPostProcessor.postProcessPropertyValue(PS: postProcessPropertyValue這個方法主要是注入被注解修飾的屬性)是否執行, 一般情況就是返回 true
  • InstantiationAwareBeanPostProcessor 的 postProcessProperty: 這是一個非常重要的方法, 主要完成Bean中被注解注釋的屬性的注入(比如:AutowiredAnnotationBeanPostProcessor 處理 @Autowired, @Value;RequiredAnnotationBeanPostProcessor處理 @Resource; PersistenceAnnotationBeanPostProcessor處理@PersistenceContext等注解)(PS:SpringMVC 的@RequestMapping 與 事務的 @Transactional 又是不同的處理邏輯)
  • SmartInstantiationAwareBeanPostProcessor 的 predictBeanType: 預測Class的類型, 當系統中發現無法確定Bean類型,并且存在SmartInstantiationAwareBeanPostProcessor,就會通過這個方法來獲取對應的class類型(PS: 這個方法主要的實現在 AbstractAutoProxyCreator里面)
  • SmartInstantiationAwareBeanPostProcessor 的 determineCandidateConstructors: 預測類的構造函數, 之所以有這個方法, 主要存在 @Lookup 注解(PS: 這個注解很少使用), 這個determineCandidateConstructors方法在實例化 Bean的過程中會被調用具體看
    AbstractAutowireCapableBeanFactory.determineConstructorsFromBeanPostProcessors方法
  • SmartInstantiationAwareBeanPostProcessor的 getEarlyBeanReference: 預測Bean實例, 在
    AbstractAutoProxyCreator中這個方法與postProcessAfterInitialization中只有一個會執行
    Bean 的代理過程(PS: 這是為什么呢, 看看 earlyProxyReferences就知道了, 兩個方法在執行wrapIfNecessary 都會通過 earlyProxyReferences 判斷是否已經創建好 AOP 對象); 對于這個getEarlyBeanReference 方法是在 Bean 被提早暴露時才會調用
    舉例:
    兩個類: class A { B b;}; class B { A a; }; 都注入到 Spring 容器,
  • XmlBeanDefinitionReader 將描述 A,B兩個類的xml 文件讀入, 并解析成 BeanDefinition, 然后注入到 DefaultListableBeanFactory中;
  • DefaultListableBeanFactory 通過 getBean 方法開始實例化這兩個類, 在創建 A 的時, 發現A是單例, 其容器允許循環引用, 并且 A 不在 map ->
    singletonsCurrentlyInCreation(表示類是否在創建) 中, 則將 A 包裝成 ObjectFactory 類,
    放入單例工廠中, 已備被其他創建的類引用, 而 ObjectFactory 中是通過
    AbstractAutowireCapableBeanFactory.getEarlyBeanReference -->
    SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference -->
    AbstractAutoProxyCreator.getEarlyBeanReference 來暴露創建的動態代理對象
  • 而在實例化 A 后, 發現 A 依賴于 B(這里的依賴信息可能存在于xml 或通過 @Autowired/@Resource 注解), 則開始創建類 B
  • 同樣在創建類 B 時, 發現 B 依賴于 A, 所以直接通過 earlySingletonObjects 來獲取上面提早暴露的 ObjectFactory, 接著會
    AbstractAutowireCapableBeanFactory.getEarlyBeanReference -->
    SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference -->
    AbstractAutoProxyCreator.getEarlyBeanReference 來得到最終暴露出來的 A 對象
    BeanPostProcessor 的分類, 各個子類的作用, 包括 BeanFactory 中如何解決循環引用(只有scope是單例,
    并且依賴不是存在在構造函數中才能解決循環引用) 進行了介紹, 后續會對個別 BeanPostProcessor 詳細的解析
  • IOC 主要組件 FactoryBean
    FactoryBean: Spring容器中某類特定Bean的工廠類(這里其實就涉及到了抽象工廠模式), FactoryBean 充斥著整個IOC容器, 一開始接觸 FactoryBean的同學可能不深刻理解這個類的好處, 其實看一下 ProxyFactoryBean(生成動態代理的 FactoryBean), ScheduledExecutorFactoryBean(生成定時線程執行器的 FactoryBean), TransactionProxyFactoryBean(基于目標 Target 生成通過切面控制事務的動態代理類), JobDetailFactoryBean(生成基于 org.quartz.JobDetail 的實例), 就能知道 FactoryBean 主要其實是對于一些創建過程復雜的類進行通過操作的類,

  • IOC 主要組件 BeanFactory
    BeanFactory: 是Spring IOC 容器的頂層接口, 其中定義了獲取Bean的一般接口, 如下:

  • // Spring 的 Bean 容器最頂層的接口, 定義了 Ioc 容器的基本規范 public interface BeanFactory {// 通過在BeanName名字前面加 & 來獲取生成對象的 factoryString FACTORY_BEAN_PREFIX = "&";// 通過 Bean 的名字, 獲取對應的實例Object getBean(String name) throws BeansException;// 獲取指定名稱的 Bean, 其中 requiredType 指的是 Bean的類型<T> T getBean(String name, Class<T> requiredType) throws BeansException;// 獲取指定名稱的 Bean<T> T getBean(Class<T> requiredType) throws BeansException;// 獲取指定名稱的 Bean, 其中 args 指的是 構造函數/工廠方法的參數Object getBean(String name, Object... args) throws BeansException;// 獲取指定類型的 Bean, 其中 args 指的是 構造函數/工廠方法的參數<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;// 判斷容器是否含有 Beanboolean containsBean(String name);// 這個名稱對應的 Bean 是否是 singleton 類型boolean isSingleton(String name) throws NoSuchBeanDefinitionException;// 這個名稱對應的 Bean 是否是 prototype 類型boolean isPrototype(String name) throws NoSuchBeanDefinitionException;// 判斷指定名稱對應的 Bean 是否與 typeToMatch 相匹配(這個方法使用得非常多)boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;// 判斷指定名稱對應的 Bean 是否與 typeToMatch 相匹配(這個方法使用得非常多)boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;// 獲取指定 Name 的 bean 類型(PS: 一個特例, 若遇到 FactoryBean, 則會通過 FactoryBean.getObjectType 來獲取最終對象的類型)Class<?> getType(String name) throws NoSuchBeanDefinitionException;// 獲得 Bean 的別名String[] getAliases(String name); }

    上面接口主要定義了獲取 Bean 的接口, 至于 BeanFactory 的繼承(HierachicalBeanFactory), 自動裝配(AutowireCapableBeanFactory), 批量獲取 bean(ListableBeanFactory) 這些特性都是由子接口進行定義, 如下圖:

    乍一看, 圖中類/接口好復雜, 沒事, 我們一層一層梳理:

    接口:第一層: BeanFactory: 這個接口里面定義獲取 Bean 的基礎方法第二層: HierarchicalBeanFactory: 這個接口定義了獲取 parentBeanFactory 的方法(PS: 這里其實也存在著委派機制, 當子BeanFactory 獲取不到bean時, 會通過父BeanFactory來進行獲取, 但是反過來,BeanFactory若獲取不到Bean, 則不會再到子BeanFactory中獲取, 這種父子BeanFactory形式通常在于:Tomcat的web.xml里面配置 ContextLoaderListener.contextInitialized --> ContextLoader.initWebApplicationContext --> 通過反射直接創建 XmlWebApplicationContext <-- 這個是 parentBeanFactory, 與之對應的 子BeanFactory 是 由 HttpServletBean.init() --> FrameworkServlet.initServletBean --> FrameworkServlet.initWebApplicationContext --> FrameworkServlet.createWebApplicationContext(這時會將上面的父beanFactory設置到子BeanFactory)) ListableBeanFactory: (基于類型)獲取容器中所有 BeanNames, 獲取被注解注釋的 BeanName 等方法AutowireCapableBeanFactory: 這里面定義了, 創建Bean, 自動裝配 Bean, 初始化 Bean, 為特定 Bean 解決對應依賴屬性的方法第三層: ConfigurableBeanFactory: 增加配置Bean功能的BeanFactory, 這個接口, 繼承 SingletonBeanFactory, 具備了注冊單例bean的接口, 除此之外 其中還定義了配置 ConversionServere(Spring里面的類型轉換器, Spring 默認的是 DefaultConversionService, 主要是完成數據類型的轉換器的注冊); 配置 BeanPostProcessor(Bean后置處理器)的方法, 銷毀 Bean的方法ConfigurableListableBeanFactory: 這個接口里面定義了 preInstantiateSingletons (預實例化Bean的方法), 獲取指定名稱的 BeanDefinition 的方法等(PS: 這個第三層接口主要是針對第二層接口的功能延伸, 其中 ConfigurableBeanFactory 具備了 注冊單例Bean的功能) 實現類:AbstractBeanFactory: 這個類繼承了 FactoryBeanRegistrySupport 具備了注冊單例+支持FactoryBean的能力, 本身也實現了創建 Bean 的主邏輯(getBean 方法), 并留下了 createBean, getBeanDefinition, containsBeanDefinition 等模板方法AbstractAutowireCapableBeanFactory: 這個類繼承了 AbstractBeanFactory 并實現了模板方法 createBean, 并實現了接口 AutowireCapableBeanFactory, 完成了對 BeanPostProcessor 的處理DefaultListableBeanFactory: 這個類是 Spring IOC 里面功能最全的 Bean 容器, 我們常用的 ApplicationContext 都是基本都是在內部有個 DefaultListableBeanFactory(基于 ApplicationContext 繼承 BeanFactory, 所以你也可以將這種程序設計方式視為 代理方式) PS: 一開始看 Spring IOC 時被 BeanFactory 的繼承接口給嚇住了(哇 這么多的接口繼承關系, 層級又是這么多), 結果才發現, 這么多接口中只有第一層與第二層接口之間有明顯的擴展, 而下面的接口, 都是逐漸逐漸擴充對應的方法

    上面是 BeanFactory 的接口設計及實現, 接口層面主要是3級, 都是對容器功能一點一點的擴充, 而其中 AbstractBeanFactory 設計了創建類的主邏輯(getBean方法), 并且預留了創建類的模板方法(createBean), 而最終的實現類就是 DefaultListableBeanFactory, 工作中常用的:

  • XmlBeanFactory(基于 XmlBeanDefinitionReader讀取xml配置的Bean依賴關系)

  • XmlWebApplicationContext(用于web容器中的BeanFactory)

  • ClassPathXmlApplicationContext(通過在 classpath 下面查找指定文件的 BeanFactory)

  • FileSystemXmlApplicationContext(直接通過文件相對路基獲取xml配置文件的 BeanFactory)

  • AnnotationConfigWebApplicationContext (通過掃描指定目錄下面的 class 文件, 并將被特定注解修飾的額類加載到容器中的 BeanFactory)
    都是或多或少的用到 DefaultListableBeanFactory(要是繼承, 要么就是將DefaultListableBeanFactory設置為其內部的一個變量)

  • IOC 總結
    上面簡單的介紹了一下 Spring IOC 里面的主要組件, 其中涉及到的組件還是比較多的, 一開始進行看源碼時可能被浩瀚的代碼給淹沒, 從而恐懼, 接著就放棄了(相信很多人都會經歷過這幾個過程), 當然我也經歷過, 當然直到現在自己對 Spring 里面有些細節的東西還不是非常了解, 但其實沒關系, 個人覺得只要把握主要的設計思想以及常見的架構設計就可以了!(畢竟全部弄精還是非常耗時的一個工程)

  • https://www.jianshu.com/p/2e6103f571f1

    總結

    以上是生活随笔為你收集整理的Spring IOC 组件概述的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。