IOC(inverse of control,控制-反轉)
一、ioc概述
1.ioc的類型
ioc主要可以劃分成三種類型:構造函數注入、屬性注入和接口注入
2.通過容器完成依賴關係注入:
通過xml的方式配置Bean,在容器啓動時,spring根據xml配置文件的
描述信息自動實例化Bean並完成依賴關係的裝配,
這種實例化並注入依賴的能力是通過java的反射來實現的
二、相關java基礎知識
java語言允許通過程序化的方式間接對Class進行操作。
Class文件有類裝載器裝載後, 在JVM中將形成一份描述Class結構的元信息對象,
通過該元信息對象可以獲知Class的結構信息,如構造函數、屬性和方法等。
Java允許用戶藉由這個與Class相關的元信息對象間接調用Class對象的功能,
這就爲使用程序化方式操作Class對象開闢了途徑
1、類裝載器就ClassLoader
類裝載器就是尋找類的字節碼文件並構造出類在JVM內部表示對象的組件
類裝載器把一個類裝入JVM中,需要經過一下步驟:
(1)裝載:查找和導入Class文件
(2)鏈接:執行校驗、準備和解析步驟,其中解析步驟是可以選擇的。
①校驗:檢查載入Class文件數據的正確性
②準備:給類的靜態變量分配存儲空間
③解析:將符號引用轉換爲直接引用
(3)初始化:對類的靜態變量、靜態代碼塊執行初始化工作
JVM裝載類的時使用“全盤負責委託機制”
“全盤負責”:是指當一個ClassLoader裝載一個類時,除非顯式地使用另一個“ClassLoader”,
該類所依賴及引用的類也有這個ClassLoader載入;
“委託機制”:是指先委託父裝載器尋找目標類,只有在找不到的情況下才從自己的類路徑中查找
並裝載目標類;
正因爲有了“全盤負責委託機制”,java.lang.String 永遠是由根裝載器來裝載的,
避免有人編寫一個惡意的基礎類(例如String)裝載到JVM中
2.java反射機制
Class反射對象描述類的語義結構,
從Class對象可以獲取構造函數、成員變量、方法類等類元素的反射對象
主要的反射類有三個:Controller、Method、Field 其他還有package、AnnotatedElement反射類
在訪問private或protected成員變量或方法時,必須通過setAccessible(boolean access)方法取消
java語言檢查,否則將拋出IllegalAccessException
三、資源訪問利器 Resource
1、資源抽象接口
spring Resource接口爲應用提供了更強的底層資源訪問能力。該接口擁有對應不同資源類型的實現類
主要方法:
> boolean exists(): 資源是否存在
> boolean isOpen(): 資源是否打開
> URL getUTL() throws IOException: 如果底層資源可以表示成URL,則該方法返回對應不同類型的實現類
> File getFile() throws IOException: 如果底層資源對應一個文件,則該方法返回對應的File對象
> InputStream getInputStream() throws IOException: 返回資源對應的輸入流
> WritableResource: 可寫資源接口 實現類有FileSystemResource和PathResource
> ByteArrayResource: 二進制數組表示的資源
> ClassPathResource: 類路徑下的資源
> FileSystemResource: 文件系統資源
> InputStreamResource: 以輸入流返回表示的資源
> ServletContextResource: 爲訪問Web容器上下文中的資源而設計的類
> UrlResource: 使用戶能夠訪問任何可以通過URL表示的資源
> PathResource: spring4.0提供讀取資源文件的一個通用類
2、資源加載
spring能通過不同的資源地址前綴識別不同的資源類型。支持Ant風格通配符資源地址:? * **
資源地址前綴有:classpath:、file:、http://、ftp://等。
或者是沒有前綴,根據ApplicationContext的具體實現類採用對應類型的Resource
在發佈時如果資源配置文件被打包到jar包中。recource.getFile就無法讀取了,
從而造成部署實施時出現意想不到的問題。因此我們建議儘量以流的方式讀取
避免環境不同造成問題
四、BeanFactory和ApplicationContext
spirng通過配置文件描述Bean與Bean之間的依賴關係,利用Java語言的反射功能實例化Bean並建立Bean之間的依賴關係。
springIOC的容器在完成這些底層工作的基礎上還提供了Bean實例緩存、生命週期管理、Bean實例代理、事件發佈、資源裝載等高級服務。
BeanFactory是spring框架最核心的接口,它提供了高級IOC的配置機制
BeanFactory是IOC容器,ApplicationContext爲應用上下文,也稱爲Spring容器
BeanFactort是Spring框架的基礎設施面向Spring本身;ApplicationContext面向使用Spring框架的開發者
1.BeanFactory在初始化容器時沒有實例化Bean,直到第一次訪問某個Bean時才實例化目標Bean
而ApplicationContext則在初始化應用上下文時就實例化所有單實例的Bean。
因此ApplicationContext的初始化時間會比BeanFactory稍長一些,不過稍後的調用則沒有“第一次懲罰”的問題
2.通過HierarchicalBeanFactory接口,spring的IOC容器可以建立父子層級關聯的容器體系
子容器可以訪問父容器中的Bean,但父容器不能訪問子容器中的Bean。
在容器內,Bean的Id必須是唯一的,但子容器可以擁有一個和父容器id相同的Bean。
五、Bean的生命週期
Bean生命週期多個特定的生命階段組成,每個生命階段都開出了一扇門,允許外界藉由此門對Bean施加控制
spring中可以從兩層面定義Bean的生命週期:
第一個層面是Bean的作用範圍
第二個層面是實例化Bean時所經歷的一系列階段
1.BeanFactory中Bean的生命週期
1.當調用者通過getBean(beanName)向容器請求某一個Bean時,如果容器註冊了
org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor接口
,實例化Bean之前,將調用接口的postProcessBeforeInstantiation方法。
2.根據配置情況調用Bean構造函數或工廠方法實例化Bean
3.如果容器註冊了InstantiationAwarePostProcessor接口,那麼在實例化Bean之後,
用該接口的postProcessAfterInstantiation()方法,可在這裏對已經實例化的對象進行梳理打扮
4.如果Bean配置了屬性信息,那麼容器在這一步着手將配置值設置到Bean對應的屬性中,不過在設置每個屬性之前
將先調用InstantiationAwareBeanPostProcessor接口的postProcessValues()方法。
5.調用Bean的屬性設置方法設置屬性值
6.如果Bean實現了 org.springframework.beans.factory.BeanNameAWare 接口,則將調用setBeanName()接口方法,
將配置文件中該Bean對應的名稱設置到Bean中
7.如果Bean實現了org.springframework.beans.factory.BeanFactoryAware接口,則將調用setBeanFactory()接口方法,
將BeanFactory容器實例設置到Bean中。
8.如果BeanFactory裝配了org.springframework.beans.factory.config.BeanPostProcessor後處理器,
則將嗲用BeanPostProcessor的Object postProcessBeforeInitialzation(Object bean,String beanName)接口方法
對Bean進行加工操作。
其中入參bean是當前正在處理的Bean,而beanName是當前Bean的配置名,返回的對象爲加工處理後的Bean
用戶可以使用該方法對某些Bean進行特殊處理,甚至改變Bean的行爲。
BeanPostProcessor在Spring框架中佔有重要的地位,爲容器提供對Bean後續加工處理的切入點
Spring提供的AOP、動態dialing等功能都通過BeanPostProcessor實施
9.如果Bean實現了InitialzaingBean接口,則將調用接口的afterPropertiseSet()方法
10.如果<bean>中通過init-method屬性定義了初始化方法,則將執行這個方法。
11.BeanPostProcessor後處理器定義了兩個方法:
其一是postProcessBeforeInitialization(),在第8步調用;
其二是Object postProcessAfterInitialization(Object bean,String beanName),這個方法在此時調用,
容器再次獲得對Bean進行加工處理的機會
12.如果在<bean>中指定Bean的作用範圍爲scope = "prototype",則將Bean返回給調用者,調用者負責Bean後續的生命管理,
spring不再管理這個Bean的生命週期。如果將作用範圍設置爲scope="singleton",則將Bean放入SpringIoc容器的緩存池中,
並將Bean引用返回給調用者,Spring繼續對這些Bean進行後續的生命管理。
13.對於scope="singleton"的Bean(默認情況),當容器關閉時,將觸發Spring對Bean後續生命週期的管理工作。
如果Bean實現了DisposableBean接口,將調用接口destroy方法,可以在此編寫釋放資源,記錄日誌等操作。
14.對於scope="singleton"的Bean,如果通過<bean>的destroy-method屬性指定了Bean的銷燬方法,那麼Spring將執行Bean等的這個方法,
完成Bean資源的釋放等操作。
BeanFactory生命週期總結
Bean完整的生命週期中方法大致可以分爲四類:
1.Bean自身的方法:
如調用Bean構造函數實例化Bean、調用Setter設置Bean的屬性值及通過<bean>的init-method和destroy-method所指定的方法
2.Bean級生命週期接口方法:
如BeanNameAware、BeanFactoryAware、InitializatingBean和DisposableBean,這些接口方法有Bean類直接實現
3.容器級生命週期接口方法:
由InstantiationAwareBeanPostProcessor和BeanPostProcessor這兩個接口實現的,一般稱他們的實現類爲“後處理器”。
後處理器接口一般不由Bean本身實現,他們獨立於Bean,實現類以容器附加裝置的形式註冊到Spring容器中,並通過接口
反射爲Spring容器掃描識別。當Spring容器創建任何Bean的時候,這些後處理器都會發生作用,所以這些處理器的影響是全局性的。
當然,用戶可以通過合理地編寫後處理器,讓其僅對感興趣的Bean進行加工處理
4.工廠後處理器接口方法:
包括AspectJWeavingEnable、CustomerAutowireConfigurer、ConfigurationClassPostProcessor等方法。
工廠後處理器也是容器級的,在應用上下文裝配配置文件後立即調用
2.ApplicationContext中Bean的生命週期
1、Bean在應用上下文中的生命週期與在BeanFactory中類似,不同的是在第一步前如果配置了工廠後處理器接口BeanFactoryPostProcessor
的實現類,則在應用上下文加載配置後,初始化Bean實例之前將調用這些BeanFactoryPostProcessor對配置信息進行加工處理。
工廠後處理器是容器級的,僅在應用上下文初始化時調用一次,其目的是完成一些配置文件的加工處理工作
2.如果Bean實現了org.springframework.context.ApplicationContextAware接口,則會在第八步setBeanFactory後
調用setApplicationContext方法
3.ApplicationContext與BeanFactory的另一個最大不同是:
ApplicationContext會利用java反射機制自動識別出配置文件中定義的BeanPostProcessor、InstantiationAwareBeanPostProcessor
和BeanFactoryPostProcessor,並自動將它們註冊到上下文中
BeanFactory則在代碼中通過手工調用addBeanPostProcessor()方法進行註冊