天天看點

一篇文章講透spring ioc (概念、原理、執行個體、應用場景、面試題)

    • ioc概念
    • 優勢
    • 原理
    • 常見api
    • 執行個體
    • 應用場景
    • 常見面試題
        ioc概念、優勢、原理、常見使用、執行個體、應用場景 ioc概念與定義:ioc翻譯成中文為控制反轉。意思可以了解為類與類之間的依賴通過容器來控制、配置實作;換一種方式可以這麼了解 原來類與類之間在編譯時即産生了依賴,即new 對象時,已建立好兩者之間的依賴關系;ioc機制将兩者之間的依賴關系通過容器進行控制,通過注解的方式,在運作時階段,動态的将某種依賴注入到類當中。 優勢:
    • 減少了代碼之間的耦合度
    • 增強了類的擴充性
    • 簡化配置,提高代碼複用性
      原理:ioc主要是通過反射原理實作 ,設計流程如下:
    一篇文章講透spring ioc (概念、原理、執行個體、應用場景、面試題)
                                                      ioc反射原理實作 流程解析: 
    1. 根據路徑、資源名稱等方式,将xml檔案、注解類加載到容器中
    2. 通過BeanDefinitionReader将對象解析成BeanDefinition執行個體
    3. 建立BeanFactory工廠(注冊前後需要添加bean前置、後置處理器)
    4. 通過BeanFactory工廠将對象執行個體化、對象初始化(初始化前後執行前置、後置處理器)
      核心類解析:
    • BeanDefinition:  
    bean定義類,定義了bean内部的組成方式(例如class、properties、autoware等)  配置的xml檔案,annotation類的 注解都基于此定義類實作。 容器中的每一個 bean 都會有一個對應的 BeanDefinition 執行個體。該執行個體負責儲存 bean 對象的所有必要資訊,包括 bean 對象的 class 類型、是否是抽象類、構造方法和參數、其他屬性等等。
    • BeanDefinitionReader:   加載、解析資源
    bean定義類讀取接口:定義上文BeanDefinition執行個體的讀取方式。通過擷取類加載器、檔案路徑資源等方式讀取執行個體所在的xml檔案或者java類,将其加載到虛拟機中。最終将其解析成為BeanDefinition執行個體對象
    一篇文章講透spring ioc (概念、原理、執行個體、應用場景、面試題)
    • BeanFactory
    spring Bean處理的主入口,負責Bean的建立與管理。 常見使用例如  ApplicationContext、 ClassPathXmlApplicationContext 即是其中的執行個體 public void refresh() throws BeansException, IllegalStateException {    synchronized (this.startupShutdownMonitor) {       // Prepare this context for refreshing.       prepareRefresh();           // 建立bean工廠,讀取xml檔案,加載beanDefinitions到緩存中       ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();           // bean工廠前置處理       prepareBeanFactory(beanFactory);           try {        注冊bean工廠處理器          postProcessBeanFactory(beanFactory);             //執行bean工廠          invokeBeanFactoryPostProcessors(beanFactory);              // 注冊bean處理器          registerBeanPostProcessors(beanFactory);              // Initialize message source for this context.          initMessageSource();              // 初始化容器事件廣播          initApplicationEventMulticaster();              // Initialize other special beans in specific context subclasses.          onRefresh();              // 注冊事件監聽器          registerListeners();              // Instantiate all remaining (non-lazy-init) singletons.          finishBeanFactoryInitialization(beanFactory);              // Last step: publish corresponding event.          finishRefresh();       }
    •  BeanFactoryPostProcessor
    BeanFactory級别的處理,是針對整個Bean的工廠進行處理,在bean工廠初始化前後進行處理。
    • BeanPostProcessor

    bean級别的處理,針對某個具體的bean進行處理。在bean初始化操作的前後進行處理   常見api : @Controller 用于标注控制器層元件 @Service 用于标注業務層元件 @Component 用于标注這是一個受 Spring 管理的元件,元件引用名稱是類名,第一個字母小寫。可以使用@Component(“beanID”) 指定元件的名稱 @Repository 用于标注資料通路元件,即DAO元件 @Auwared 方法級别的注解,主要用在@Configuration和@Component注解的類裡,@Bean注解的方法會産生一個Bean對象,該對象由Spring管理并放到IoC容器中。引用名稱是方法名,也可以用@Bean(name = "beanID")指定元件名 @Resource 預設按名稱進行自動裝配,當找不到與名稱比對的Bean時會按類型裝配。 @Scope("protoype") 将元件的範圍設定為原型的(即多例)。保證每一個請求有一個單獨的action來處理,避免action的線程問題。   常見面試題 : 1、Spring是什麼? Spring是一個輕量級的IoC和AOP容器架構。目的是解決企業應用開發的複雜性,使用基本的JavaBean來完成以前隻可能由EJB完成的事情,并提供了更多的企業應用功能,Spring的用途不僅限于伺服器端的開發,從簡單性、可測試性和松耦合的角度而言,任何Java應用都可以從Spring中受益。 2、Spring 的優點? (1)spring屬于低侵入式設計,代碼的污染極低; (2)spring的DI機制降低了業務對象替換的複雜性; (3)容器提供了AOP技術,利用它很容易實作如權限攔截,運作期監控等功能; (4)降低了元件之間的耦合性 ,實作了軟體各層之間的解耦; (5)容器提供單例模式支援; (6)可以使用容器提供的衆多服務,如事務管理,消息服務等; (7)容器提供了衆多的輔助類,能加快應用的開發; (8)spring對于主流的應用架構提供了內建支援,如hibernate,JPA,Struts等 (9)獨立于各種應用伺服器 (10)Spring的高度開放性,并不強制應用完全依賴于Spring,開發者可以自由選擇spring的部分或全部。 4、Spring的IoC了解: (1)IOC就是控制反轉。就是對象的建立權反轉交給Spring,由容器控制程式之間的依賴關系,作用是實作了程式的解耦合,而非傳統實作中,由程式代碼直接操控。(依賴)控制權由應用代碼本身轉到了外部容器,由容器根據配置檔案去建立執行個體并管理各個執行個體之間的依賴關系,控制權的轉移,是所謂反轉,并且由容器動态的将某種依賴關系注入到元件之中。BeanFactory 是Spring IoC容器的具體實作與核心接口,提供了一個先進的配置機制,使得任何類型的對象的配置成為可能,用來包裝和管理各種bean。 (2)最直覺的表達就是,IOC讓對象的建立不用去new了,可以由spring自動生産,這裡用的就是java的反射機制,通過反射在運作時動态的去建立、調用對象。spring就是根據配置檔案在運作時動态的去建立對象,并調用對象的方法的。

    (3)Spring的IOC有三種注入方式 : 第一是根據屬性注入,也叫set方法注入; 第二種是根據構造方法進行注入; 第三種是根據注解進行注入。 詳細的說: (4)IoC,控制反轉:将對象交給容器管理,你隻需要在spring配置檔案總配置相應的bean,以及設定相關的屬性,讓spring容器生成類的執行個體對象以及管理對象。在spring容器啟動的時候,spring會把你在配置檔案中配置的bean都初始化以及裝配好,然後在你需要調用的時候,就把它已經初始化好的那些bean配置設定給你需要調用這些bean的類。就是将對象的控制權反轉給spring容器管理。 (5)DI機制(Dependency Injection,依賴注入):可以說是IoC的其中一個内容,在容器執行個體化對象的時候主動的将被調用者(或者說它的依賴對象)注入給調用對象。比如對象A需要操作資料庫,以前我們總是要在A中自己編寫代碼來獲得一個Connection對象,有了 spring我們就隻需要告訴spring,A中需要一個Connection,至于這個Connection怎麼構造,何時構造,A不需要知道。在系統運作時,spring會在适當的時候制造一個Connection,然後像打針一樣,注射到A當中,這樣就完成了對各個對象之間關系的控制。 IoC讓互相協作的元件保持松散的耦合,而AOP程式設計允許你把遍布于應用各層的功能分離出來形成可重用的功能元件。 5、BeanFactory和ApplicationContext有什麼差別? BeanFactory和ApplicationContext是Spring的兩大核心接口,而其中ApplicationContext是BeanFactory的子接口。它們都可以當做Spring的容器,生成Bean執行個體的,并管理容器中的Bean。 (1)BeanFactory:是Spring裡面最底層的接口,提供了最簡單的容器的功能,負責讀取bean配置文檔,管理bean的加載與執行個體化,維護bean之間的依賴關系,負責bean的生命周期,但是無法支援spring的aop功能和web應用。 (2)ApplicationContext接口作為BeanFactory的派生,因而具有BeanFactory所有的功能。而且ApplicationContext還在功能上做了擴充,以一種更面向架構的方式工作以及對上下文進行分層和實作繼承,相較于BeanFactorty,ApplicationContext還提供了以下的功能: ①預設初始化所有的Singleton,也可以通過配置取消預初始化。 ②繼承MessageSource,是以支援國際化。 ③資源通路,比如通路URL和檔案。 ④事件機制。 ⑤同時加載多個配置檔案。 ⑥以聲明式方式啟動并建立Spring容器。 ⑦載入多個(有繼承關系)上下文 ,使得每一個上下文都專注于一個特定的層次,比如應用的web層。 (3)①BeanFactroy采用的是延遲加載形式來注入Bean的,即隻有在使用到某個Bean時(調用getBean()),才對該Bean進行加載執行個體化,這樣,我們就不能發現一些存在的Spring的配置問題。如果Bean的某一個屬性沒有注入,BeanFacotry加載後,直至第一次使用調用getBean方法才會抛出異常。 ②而ApplicationContext則相反,它是在容器啟動時,一次性建立了所有的Bean。這樣,在容器啟動時,我們就可以發現Spring中存在的配置錯誤,這樣有利于檢查所依賴屬性是否注入。 ApplicationContext啟動後預載入所有的單執行個體Bean,通過預載入單執行個體bean ,確定當你需要的時候,你就不用等待,因為它們已經建立好了。   ③相對于基本的BeanFactory,ApplicationContext 唯一的不足是占用記憶體空間。當應用程式配置Bean較多時,程式啟動較慢。 (4)BeanFactory通常以程式設計的方式被建立,ApplicationContext還能以聲明的方式建立,如使用ContextLoader。 (5)BeanFactory和ApplicationContext都支援BeanPostProcessor、BeanFactoryPostProcessor的使用,但兩者之間的差別是:BeanFactory需要手動注冊,而ApplicationContext則是自動注冊。 6、 解釋Spring支援的幾種bean的作用域。 Spring容器中的bean可以分為5個範圍:

    (1)singleton:這種bean範圍是預設的,這種範圍確定不管接受到多少個請求,每個容器中隻有一個bean的執行個體,單例的模式由bean factory自身來維護。 (2)prototype:原形範圍與單例範圍相反,為每一個bean請求提供一個執行個體。 (3)request:在請求bean範圍内會每一個來自用戶端的網絡請求建立一個執行個體,在請求完成以後,bean會失效并被垃圾回收器回收。 (4)Session:與請求範圍類似,確定每個session中有一個bean的執行個體,在session過期後,bean會随之失效。 (5)global-session:global-session和Portlet應用相關。當你的應用部署在Portlet容器中工作時,它包含很多portlet。如果你想要聲明讓所有的portlet共用全局的存儲變量的話,那麼這全局變量需要存儲在global-session中。全局作用域與Servlet中的session作用域效果相同。 7、請解釋Spring Bean的生命周期? 首先說一下Servlet的生命周期:執行個體化,初始init,接收請求service,銷毀destroy; Spring上下文中的Bean生命周期也類似,如下: (1)執行個體化一個Bean--也就是我們常說的new; (2)按照Spring上下文對執行個體化的Bean進行配置--也就是IOC注入; (3)如果這個Bean已經實作了BeanNameAware接口,會調用它實作的setBeanName(String)方法,此處傳遞的就是Spring配置檔案中Bean的id值; (4)如果這個Bean已經實作了BeanFactoryAware接口,會調用它實作的setBeanFactory(setBeanFactory(BeanFactory)傳遞的是Spring工廠自身(可以用這個方式來擷取其它Bean,隻需在Spring配置檔案中配置一個普通的Bean就可以); (5)如果這個Bean已經實作了ApplicationContextAware接口,會調用setApplicationContext(ApplicationContext)方法,傳入Spring上下文(同樣這個方式也可以實作步驟4的内容,但比4更好,因為ApplicationContext是BeanFactory的子接口,有更多的實作方法); (6)如果這個Bean關聯了BeanPostProcessor接口,将會調用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor經常被用作是Bean内容的更改,并且由于這個是在Bean初始化結束時調用那個的方法,也可以被應用于記憶體或緩存技術; (7)如果Bean在Spring配置檔案中配置了init-method屬性會自動調用其配置的初始化方法。 (8)如果這個Bean關聯了BeanPostProcessor接口,将會調用postProcessAfterInitialization(Object obj, String s)方法、; 注:以上工作完成以後就可以應用這個Bean了,那這個Bean是一個Singleton的,是以一般情況下我們調用同一個id的Bean會是在内容位址相同的執行個體,當然在Spring配置檔案中也可以配置非Singleton。 (9)當Bean不再需要時,會經過清理階段,如果Bean實作了DisposableBean這個接口,會調用那個其實作的destroy()方法; (10)最後,如果這個Bean的Spring配置中配置了destroy-method屬性,會自動調用其配置的銷毀方法。 另外我們這裡描述的是應用Spring上下文Bean的生命周期,如果應用Spring的工廠也就是BeanFactory的話去掉第5步就Ok了。 8、Spring中bean的加載過程: (1)擷取配置檔案資源; (2)對擷取的xml資源進行一定的處理檢驗; (3)處理包裝資源; (4)解析處理包裝過後的資源; (5)加載提取bean并注冊(添加到beanDefinitionMap中)。 9、Spring架構中的單例Beans是線程安全的麼? Spring架構并沒有對單例bean進行任何多線程的封裝處理。關于單例bean的線程安全和并發問題需要開發者自行去搞定。但實際上,大部分的Spring bean并沒有可變的狀态(比如Serview類和DAO類),是以在某種程度上說Spring的單例bean是線程安全的。如果你的bean有多種狀态的話(比如 View Model 對象),就需要自行保證線程安全。 最淺顯的解決辦法就是将多态bean的作用域由“singleton”變更為“prototype”。 10、Spring如何處理線程并發問題? Spring使用ThreadLocal解決線程安全問題。 我們知道在一般情況下,隻有有狀态的Bean才可以在多線程環境下共享,在Spring中,絕大部分Bean都可以聲明為singleton作用域。就是因為Spring對一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非線程安全狀态采用ThreadLocal進行處理,讓它們也成為線程安全的狀态,因為有狀态的Bean就可以在多線程中共享了。 ThreadLocal和線程同步機制都是為了解決多線程中相同變量的通路沖突問題。 (1)在同步機制中,通過對象的鎖機制保證同一時間隻有一個線程通路變量。這時該變量是多個線程共享的,使用同步機制要求程式慎密地分析什麼時候對變量進行讀寫,什麼時候需要鎖定某個對象,什麼時候釋放對象鎖等繁雜的問題,程式設計和編寫難度相對較大。 (2)而ThreadLocal則從另一個角度來解決多線程的并發通路。ThreadLocal會為每一個線程提供一個獨立的變量副本,進而隔離了多個線程對資料的通路沖突。因為每一個線程都擁有自己的變量副本,進而也就沒有必要對該變量進行同步了。ThreadLocal提供了線程安全的共享對象,在編寫多線程代碼時,可以把不安全的變量封裝進ThreadLocal。 (3)概括起來說,對于多線程資源共享的問題,同步機制采用了“以時間換空間”的方式,而ThreadLocal采用了“以空間換時間”的方式。前者僅提供一份變量,讓不同的線程排隊通路,而後者為每一個線程都提供了一份變量,是以可以同時通路而互不影響。 11、請解釋Spring自動裝配模式的差別? 在Spring架構中共有5種自動裝配: (1)no:這是Spring架構的預設設定,在該設定下自動裝配是關閉的,開發者需要自行在bean定義中用标簽明确的設定依賴關系。 (2)byName:該選項可以根據bean名稱設定依賴關系。當向一個bean中自動裝配一個屬性時,容器将根據bean的名稱自動在配置檔案中查詢一個比對的bean。如果找到的話,就裝配這個屬性,如果沒找到的話就報錯。 (3)byType:該選項可以根據bean類型設定依賴關系。當向一個bean中自動裝配一個屬性時,容器将根據bean的類型自動在在配置檔案中查詢一個比對的bean。如果找到的話,就裝配這個屬性,如果沒找到的話就報錯。 (4)constructor:構造器的自動裝配和byType模式類似,但是僅僅适用于與有構造器相同參數的bean,如果在容器中沒有找到與構造器參數類型一緻的bean,那麼将會抛出異常。 (5)autodetect:該模式自動探測使用構造器自動裝配或者byType自動裝配。首先,首先會嘗試找合适的帶參數的構造器,如果找到的話就是用構造器自動裝配,如果在bean内部沒有找到相應的構造器或者是無參構造器,容器就會自動選擇byTpe的自動裝配方式。 12、Spring 控制器的加載過程:(XML版) (1)Web容器建立; (2)上下文建立,但未初始化; (3)監聽器建立,并注冊到Context上; (4)上下文初始化; (5)通知到監聽者,Spring配置檔案/@Configuration加載; (6)Load-on-startup>0的ServletConfig建立,springMVC的DispatcherServlet此時建立。 PS:Spring容器時SpringMVC的父容器。Spring的AOP在Spring的上下文建立時就會建立;如果想要代理SpringMVC的控制層,需要将配置寫到SpringMVC的配置檔案下。 13、Spring 架構中都用到了哪些設計模式? (1)代理模式—在AOP和remoting中被用的比較多。 (2)單例模式—在spring配置檔案中定義的bean預設為單例模式。 (3)工廠模式—BeanFactory用來建立對象的執行個體。 (4)模闆方法—用來解決代碼重複的問題。比如. RestTemplate, JmsTemplate, JpaTemplate。 (5)前端控制器—Spring提供了DispatcherServlet來對請求進行分發。 (6)視圖幫助(View Helper )—Spring提供了一系列的JSP标簽,高效宏來輔助将分散的代碼整合在視圖裡。 (7)依賴注入—貫穿于BeanFactory / ApplicationContext接口的核心理念。 14、Spring事務的種類和各自的差別: spring支援程式設計式事務管理和聲明式事務管理兩種方式: (1)程式設計式事務管理使用TransactionTemplate或者直接使用底層的PlatformTransactionManager。對于程式設計式事務管理,spring推薦使用TransactionTemplate。 (2)聲明式事務管理建立在AOP之上的。其本質是對方法前後進行攔截,然後在目标方法開始之前建立或者加入一個事務,在執行完目标方法之後根據執行情況送出或者復原事務。聲明式事務最大的優點就是不需要通過程式設計的方式管理事務,這樣就不需要在業務邏輯代碼中摻雜事務管理的代碼,隻需在配置檔案中做相關的事務規則聲明(或通過基于@Transactional注解的方式),便可以将事務規則應用到業務邏輯中。 (3)顯然聲明式事務管理要優于程式設計式事務管理,這正是spring倡導的非侵入式的開發方式。聲明式事務管理使業務代碼不受污染,一個普通的POJO對象,隻要加上注解就可以獲得完全的事務支援。和程式設計式事務相比,聲明式事務唯一不足地方是,後者的最細粒度隻能作用到方法級别,無法做到像程式設計式事務那樣可以作用到代碼塊級别。

    15、spring的事務傳播行為: spring事務的傳播行為說的是當一個方法調用另一個方法時,事務該如何操作。 (1)PROPAGATION_REQUIRED:如果目前沒有事務,就建立一個新事務,如果目前存在事務,就加入該事務,該設定是最常用的設定。 (2)PROPAGATION_SUPPORTS:支援目前事務,如果目前存在事務,就加入該事務,如果目前不存在事務,就以非事務執行。‘ (3)PROPAGATION_MANDATORY:支援目前事務,如果目前存在事務,就加入該事務,如果目前不存在事務,就抛出異常。 (4)PROPAGATION_REQUIRES_NEW:建立新事務,無論目前存不存在事務,都建立新事務。 (5)PROPAGATION_NOT_SUPPORTED:以非事務方式執行操作,如果目前存在事務,就把目前事務挂起。 (6)PROPAGATION_NEVER:以非事務方式執行,如果目前存在事務,則抛出異常。 (7)PROPAGATION_NESTED:如果目前存在事務,則在嵌套事務内執行。如果目前沒有事務,則執行與PROPAGATION_REQUIRED類似的操作。 16、Spring事務的實作方式和實作原理: (1)劃分處理單元——IOC: 由于spring解決的問題是對單個資料庫進行局部事務處理的,具體的實作首相用spring中的IOC劃分了事務處理單元。并且将對事務的各種配置放到了ioc容器中(設定事務管理器,設定事務的傳播特性及隔離機制)。 (2)AOP攔截需要進行事務處理的類: Spring事務處理子產品是通過AOP功能來實作聲明式事務處理的,具體操作(比如事務實行的配置和讀取,事務對象的抽象),用TransactionProxyFactoryBean接口來使用AOP功能,生成proxy代理對象,通過TransactionInterceptor完成對代理方法的攔截,将事務處理的功能編織到攔截的方法中。 讀取ioc容器事務配置屬性,轉化為spring事務處理需要的内部資料結構(TransactionAttributeSourceAdvisor),轉化為TransactionAttribute表示的資料對象。 (3)對事物處理實作(事務的生成、送出、復原、挂起): spring委托給具體的事務處理器實作。實作了一個抽象和适配。适配的具體事務處理器:DataSource資料源支援、hibernate資料源事務處理支援、JDO資料源事務處理支援,JPA、JTA資料源事務處理支援。這些支援都是通過設計PlatformTransactionManager、AbstractPlatforTransaction一系列事務處理的支援。為常用資料源支援提供了一系列的TransactionManager。 (4)結合: PlatformTransactionManager實作了TransactionInterception接口,讓其與TransactionProxyFactoryBean結合起來,形成一個Spring聲明式事務處理的設計體系。                    

繼續閱讀