本篇內容包括:IOC 和 DI 的概念、Spring 容器,即 BenaFactory 與 AplicationConext 等 IOC 相關內容。
一、IOC 和 DI 的概念
1、IOC
IoC(Inversion of control )即“控制反轉”,它是一種設計思想而非一個技術實現。描述了Java 開發領域對象的創建以及管理的問題。通過Spring來管理對象的創建、配置和生命周期,這樣相當于把控制權交給了Spring,不需要人工來管理對象之間復雜的依賴關系,這樣做的好處就是解耦。
Spring 實現 IOC 的重要手段是依賴注入 DI 對象間的依賴的控制權從開發人員手中轉移到了容器中,降低了開發成本.
在 Spring 里面,主要提供了 BeanFactory 和 ApplicationContext 兩種 IOC 容器,通過他們來實現對 Bean 的管理。
2、DI
IoC 最常見以及最合理的實現方式叫做依賴注入(Dependency Injection,簡稱 DI)。
依賴注入(DI,Dependency Injection)是 Spring 實現 IOC 的重要手段,依賴注入將對象間的依賴的控制權從開發人員手中轉移到了容器中,降低了開發成本。
3、IOC 容器
在Spring里面,主要提供了 BeanFactory 和 ApplicationContext 兩種 IOC 容器,通過他們來實現對 Bean 的管理。
-
BeanFactory 粗暴簡單,可以理解為就是個 HashMap,Key 是 BeanName,Value 是 Bean 實例。通常只提供注冊(put),獲取(get)這兩個功能。我們可以稱之為 “低級容器”。
-
ApplicationContext 可以稱之為 “高級容器”。因為他比 BeanFactory 多了更多的功能。他繼承了多個接口。因此具備了更多的功能。
二、Spring 容器設計
1、BenaFactory
BenaFactory 可以說是 IOC 最頂層的接口,其定義了一個 IOC 容器的基本規范,可以說 BenaFactory 就是一個低配版的 IOC 容器,其定義了 IOC 容器最基本的功能
BeanFactory 使用控制反轉對應用程序的配置和依賴性規范與實際的應用代碼進行分離,BeanFactory 實例化后并不會自動實例化 Bean,只有當 Bean 被使用時才會對其進行實例化與依賴關系的裝配。
public interface BeanFactory {//對 FactoryBean 的轉義定義,因為如果使用 bean 的名字檢索 FactoryBean 得到的對象是工廠生成的對象,如果需要得到工廠本身,需要轉義。String FACTORY_BEAN_PREFIX = "&";//根據 bean 的名字,獲取在 IOC 容器中得到 bean 實例。Object getBean(String name) throws BeansException;//根據 bean 的名字和 Class 類型來得到 bean 實例,增加了類型安全驗證機制。<T> T getBean(String name, Class<T> requiredType) throws BeansException;Object getBean(String name, Object... args) throws BeansException;<T> T getBean(Class<T> requiredType) throws BeansException;<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);//提供對 bean 的檢索,看看是否在 IOC 容器有這個名字的 bean。boolean containsBean(String name);//根據 bean 名字得到 bean 實例,并同時判斷這個 bean 是不是單例。boolean isSingleton(String name) throws NoSuchBeanDefinitionException;//根據 bean 名字得到 bean 實例,并同時判斷這個 bean 是不是原型。boolean isPrototype(String name) throws NoSuchBeanDefinitionException;//判斷 bean 名字和 Type 判斷 JavaBean 是否匹配指定的類型boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;//得到 bean 實例的 Class 類型@NullableClass<?> getType(String name) throws NoSuchBeanDefinitionException;@NullableClass<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;//得到 bean 的別名,如果根據別名檢索,那么其原名也會被檢索出來String[] getAliases(String name);}
可以看到,在 BeanFactory 里只對 IOC 容器的基本行為作了定義,根本不關心你的 Bean 是如何定義怎樣加載的。而要知道 Bean 是如何定義怎樣加載的,我們需要看具體的 IOC 容器實現,Spring 提供了許多 IOC 容器的 實現 。比如 GenericApplicationContext 與 ClasspathXmlApplicationContext 。
2、AplicationConext
ApplicationContext 是 Spring 中的核心接口和容器,允許容器通過應用程序上下文環境創建、獲取、管理 bean。在構建容器的時候,創建對象采用的策略是立即加載的方式,即只要一讀取完配置文件就立即創建配置文件中配置的對象(BeanFactory采用的是延遲加載的方式,什么時候根據 id 獲取對象了,什么時候才真正地創建對象)。
從以上類圖我們可以看出 ApplicationContext 繼承了 6 個接口,除了繼承自 BeanFactory 的 HierarchicalBeanFactory 和 ListableBeanFactory 以外,還包括了:EnvironmentCapable、
ApplicationEventPublisher、ResourcePatternResolver 和 MessageSource。
- EnvironmentCapable:簡單地說就是獲取環境變量,定義了 ApplicationContext 啟動時的環境,為應用程序環境的兩個關鍵方面建模:配置文件和屬性;
- ApplicationEventPublisher:主要是做事件(ApplicationEvent)傳播、事件發布的功能;
- ResourcePatternResolver:主要是做資源(Resource)加載,支持多種類型加載;
- MessageSource:國際化,國際化簡而言之就是說國際通用的意思,那就是需要不同的語言進行翻譯,這個是可以自定義的,在資源文件夾下創建。
### Spring 的三個主要實現類
- ClassPathXmlApplicationContext:可以加載類路徑下的配置文件,要求配置文件必須在類路徑之下;
- FileSystemXmlApplicationContext:可以加載磁盤中任意路徑下的配置文件,要求具有訪問權限;
- AnnotationConfigApplicationContext:用于讀取注解創建容器。