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

歡迎訪問 生活随笔!

生活随笔

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

javascript

Spring-beans架构设计原理

發布時間:2025/3/21 javascript 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring-beans架构设计原理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

IOC

IOC,官方給的定義是依賴注入(Dependency Injection)或者控制反轉(Inversion of Control)。光從字面理解起來還是比較費勁。但任何一種模式都是來自人的行為思考方式,只要想象下日常生產過程,在生產之前是客戶下單,單子會詳細注明需要的產品,包括產品的各方面規格屬性,然后工廠據此生產。

IOC就是一個類似的過程,用戶聲明要什么,ioc就給用戶生產什么。在過程中用戶只是給出需求清單,而不用再費勁去new,以及不停設置各種屬性。

Spring ioc

Spring-beans是ioc最著名的實現,而且已經沒有之一,現在幾乎就是ioc的代名詞。雖然更多人傾向認為beans只是工廠,context才是容器,但context本身更類似是beans的外觀--由它驅動beans,并且對內組合beans的功能;而且context本身也是基于beans之上的。spring最下方最牢靠的地基只有beans,它是spring的基石組件,所有的我們已知的spring組件都是基于它。

spring-beans整體架構

Spring-beans提供的優秀的可擴展能力使spring幾乎能包容一切,用戶只需遵循spring beans的相關規范--spring.schema定義配置文檔的文法規范,spring.handler定義客戶化配置的解析工具--就可以將bean接入到spring容器里。Bean接入后還可以通過實現BeanPostProcessor或者init-method對bean做后處理甚至替換bean。

Spring-beans的優秀設計使spring越來越像是一個生態圈,基于beans,aop、context、mvc、annotation等強大的組件都被接入進來,除此還有一些優秀的第三方組件,例如dubbo等。

以aop為例,先在parse階段對aop的配置生成Advised bean(Advisor),然后在所有bean的后處理階段get Advised bean,并通過filter判斷是否適應于當前bean,適用則會對bean織入advice。后面如果有時間會專門做篇aop,這里不再繼續深入。

Dubbo和aop略有區別,dubbo的擴展選擇了init method中的afterPropertiesSet,所有嚴格意義上dubbo是無法去spring的,雖然dubbo聲明是可以,但其實只能不適用spring功能,而不能去spring jar,dubbo bean在init階段生成ref,其實也是個代理--封裝了遠程訪問的細節。

Bean定義

Spring-beans的核心實體是BeanDefinition和BeanFactory。前者映射我們的定義,后者則是依據定義生產bean的工廠。

上圖是spring beans的靜態結構圖,更多是偏重于bean解析,因為1. 理解了bean解析也就理解了一半spring擴展能力;2.BeanFactory的復雜不在于類之間的組織結構,而在于復雜的調用鏈路,也就沒必要是靜態結構方面做過多說明。需要說明的是,這只是概念模型,并不完全映射到類,因為spring的抽象層次太高,一個概念實體功能往往由多個類協同完成,畫起來比較費勁,就類似BeanFactory,光搞清楚各個BeanFactory之間的關系就理得頭痛,所以都盡可能從概念層面說明。

重要實體說明

  • DefaultListableBeanFactory是BeanDefintionRegistry的默認實現,它是個適配器,用于適配BeanFactory和BeanDefintionRegistry,工廠和定義通過它統一。它由ApplicationContext初始化,并被作為BeanDefinitionReader的registry。Reader對配置文檔加載解析,生成definition并注冊到registry--其實就是DefaultListableBeanFactory,這樣工廠就擁有了類定義,bean初始化時也可以通過內部方法輕松獲取到定義。
  • NamespaceHandlerResolver用于獲取配置解析實體--NamespaceHandler。它和registry均內聚在上下文實體--ReaderContext中,parser內聚上下文從而可以間接訪問handler和registry獲得解析和注冊的能力。

其他幾個實體都比較直觀便于理解,不再一一贅述。

整體交互過程

BeanDefinitionReader是整個bean解析的聚合根,它由ApplicationContext創建,并將DefaultListableBeanFactory作為registry傳遞給它。

BeanDefinitionReader創建文檔讀取實體--DocuemntReader用于加載解析,并在step3加載文檔時創建上下文--ReaderContext傳遞給文檔讀取實體。上下文貫穿于整個解析過程始終,它在文檔讀取實體使用parser解析時也會被傳入parser中。

Parse過程是整個加載過程的核心,默認parser通過間接關聯的識別器可以依據不同配置節點進行parser切換,當讀到非默認配置時,則切換到對應客戶化parser解析。解析完成后再通過間接關聯的registry進行注冊,從而配置定義進入spring管理,待getBean時使用。

客戶化配置節點解析

客戶化配置是spring非常重要的擴展點,spring強大的擴展能力有一半功能要歸功于它,另一半中的80%就是后面要介紹的大名鼎鼎的BeanPostProcessor。不僅僅一些第三方擴展(例如開篇提到的dubbo)基于它,spring本身的很多模塊也是基于它,例如spring-aop,spring-context等等,spring體系內除了默認的beans命名空間其余都基于它擴展的。

NamespaceHandlerResolver由BeanDefinitionReader初始化,后者在第一次被訪問時讀取spring.handlers文件。.handlers文件定義namespace uri和對應處理類的映射關系。例如:

http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler

上面的這行配置就是配置聲明的解析類。

NamespaceHandlerResolver依據節點namespace獲得NamespaceHandler,然后使用handler處理自定義配置節點。

public interface NamespaceHandler {void init();BeanDefinition parse(Element element, ParserContext parserContext);BeanDefinitionHolder decorate(Node source, BeanDefinitionHolder definition, ParserContext parserContext);}

init方法注冊localName和自定義parser的關系,parser和localName的關系由handler的提供者自己注冊。例如:

public void init() {// In 2.0 XSD as well as in 2.1 XSD.registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());// Only in 2.0 XSD: moved to context namespace as of 2.1registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());}

上面就是aop注冊parser的代碼片段。config,aspectj-autoproxy這些就是localName,parse過程中不同的localName會切換到不同的parser解析。

spring先通過命名空間定位到handler,handler處理時再基于localName取相應的parser解析當前結點。比如這個配置,aop是命名空間,aspectj-autoproxy是localName。整個讀取解析過程中先通過aop找到AopNamespaceHandler,再在解析到aspectj-autoproxy節點時使用AspectJAutoProxyBeanDefinitionParser來解析。如果要研究spring源碼,一定要先找到對應parser,知道每個配置項對應到運行時的bean結構才能更好理解spring;而且parser可能會生成一些默認的BeanPostProcessor,如果意識不到這些后處理器,那么對代碼的讀取將會斷片,陷入完全無法理解的境地。比如spring-aop就是由parser默認生成AopAutoProxyCreator這個BeanPostProcessor,在bean初始化后由這個processor對bean生成代理。

Bean獲取


上圖是getBean過程,整個過程很簡潔,實際深入代碼會發現非常繁瑣。

BeanFactory和BeanDefinitionRegistry在spring里是統一的,參見第一節,圖上為了方便理解,拆成兩個概念實體。

需要注意的是第4步和第6步,bean配置時可以指定parent屬性,如果有parent,則beanFactory會對local和parent做merge,merge的策略是對parent做覆蓋,也可以理解為是對parent做繼承。這和parent bean factory完全是兩個概念,一定要區分開。

在beans的實體靜態結構里,分別注明了parent bean definition和parent bean factory。兩者都是被關聯的,而不是被繼承。后者有點像jvm的雙親委托模型,parent和child有各自的上下文,類似于jvm的命名空間。parent bean factory由applicationContext設置,無法配置。比如spring mvc就是兩個父子兩個容器,在容器refresh時相應的也會把父容器的BeanFactory設置成子容器BeanFactory的parentBeanFactory。

spring bean狀態


Bean主要經過instantiate,populate,initializeBean和registerDisposableBean4個狀態,在狀態流轉中會調用很多spring預留的擴展接口。

  • awareMethod
    如果bean繼承了BeanFactoryAware,BeanNameAware,BeanClassLoaderAware,則會在initialize階段將BeanFactory, BeanName和bean ClassLoader設置給Bean。
    注意它和ApplicationContextAware是不一樣的,后者是由BeanPostProcessor做后處理set的。

  • init method
    init method不僅僅包括配置的init-method方法還包括InitializedBean的afterPropertiesSet回調接口,這兩者均是無參的,完全可以互相替代,兩者中afterPropertiesSet調用在前。

  • BeanPostProcessor

    上文提到過,spring另一半的擴展能力是由BeanPostProcessor提供的。先看下其接口定義

    public interface BeanPostProcessor {Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException; Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException; }

    兩個方法分別在init-method調用前后,對bean做后處理。需要特別注意的就是postProcessAfterInitialization,大部分的spring擴展就是由它來完成的,比如上文提到的aop就是在這個階段對bean做后處理生成代理。相應的也可以使用postProcessBeforeInitialization,但是此時init-method并未執行,后處理需要保證init-method帶來的影響,@PostConstruct的方法執行就是在這個階段。

    實例化后處理器

    InstantiationAwareBeanPostProcessor繼承了BeanPostProcessor,主要用于在bean實例化前后做處理。

    public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException; boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException; PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException; }
    • 實例化前處理,這個方法的參數是beanClass和beanName,在bean實例化前調用,如果這個方法的返回值不為空則getBean結束,用戶收到的就是這個該方法的返回值。這個擴展點主要是留給預處理的,用戶可以直接生成一個同類型的bean,替換實際bean,此時實際bean不會被實例化。
    • 實例化后處理連同屬性后處理是spring內部非常重要的擴展點,annotation的field注入就是在這兩個階段完成。主要有兩個關鍵實現: CommonAnnotationBeanPostProcessor,該類在實例化后處理階段做屬性注入,主要用于@Resource AutowiredAnnotationBeanPostProcessor,該類在屬性后處理階段做屬性注入,主要用于@Autowired 前者還繼承了InitDestroyAnnotationBeanPostProcessor類,該類會在init-method被執行前調用@PostConstruct方法。

    總結

    以上是生活随笔為你收集整理的Spring-beans架构设计原理的全部內容,希望文章能夠幫你解決所遇到的問題。

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