官术网_书友最值得收藏!

  • Spring快速入門
  • 崔彥威 盧欣欣 王倩
  • 1707字
  • 2020-06-29 17:30:40

3.1 IOC容器

在第2章中介紹什么是依賴注入時有提到:依賴注入是組件之間的依賴關系由容器在運行期決定的,即由容器動態地將某個依賴關系注入組件之中。那什么是容器呢?既然Spring框架實現了IOC,那么Spring中的容器是什么呢?

3.1.1 容器介紹

在日常生活中,容器是指用以容納物料并以殼體為主的基本裝置,是用來盛放東西的。在編程中,容器是用來存儲和組織其他對象的對象,首先要確定容器也是對象,也可以當作bean,只是這個對象是用來存儲和組織其他對象的,那其他對象是什么呢?其他對象其實就是bean對象,這也是面向對象編程的一種體現,萬物皆對象。Spring提供了BeanFactory、ApplicationContext兩個IOC容器來管理眾多的bean對象。

3.1.2 BeanFactory

一提到工廠,我們可能就會想到富某康。工廠是一類用以生產貨物的大型工業建筑物。BeanFactory不是用來生產貨物的,而是用來生產管理bean的。BeanFactory會在bean生命周期的各個階段中對bean進行管理,并且Spring將這些階段通過各種接口暴露給我們,讓我們可以對bean進行各種處理。我們只要讓bean實現對應的接口,那么Spring就會在bean的生命周期調用我們實現的接口來處理該bean。這是怎么實現的呢?主要分為以下兩個階段。

1.bean容器的啟動

工廠要生產貨物,首先得把工廠運轉起來。同樣,bean容器要管理bean,也需要先把容器啟動起來,獲取到bean的定義信息之后才能管理。

(1)讀取bean的xml配置文件,然后將xml中每個bean元素分別轉換成BeanDefinition對象。

 public abstract class AbstractBeanDefinition extends
 BeanMetadataAttributeAccessor
 implements BeanDefinition, Cloneable {
 private volatile Object beanClass;
 private String scope = SCOPE_DEFAULT;
 private boolean abstractFlag = false;
 private boolean lazyInit = false;
 private int autowireMode = AUTOWIRE_NO;
 private int dependencyCheck = DEPENDENCY_CHECK_NONE;
 private String[] dependsOn;
 private ConstructorArgumentValues constructorArgumentValues;
 private MutablePropertyValues propertyValues;
 private String factoryBeanName;
 private String factoryMethodName;
 private String initMethodName;
 private String destroyMethodName;

BeanClass保存bean的class屬性,scope保存Bean的作用域,abstractFlag保存該bean是否抽象,lazyInit保存是否延遲初始化,autowireMode保存是否自動裝配,dependencyCheck保存是否堅持依賴,dependsOn保存該bean依賴于哪些bean(這些bean必須提取初始化),constructorArgumentValues保存通過構造函數注入的依賴,propertyValues保存通過setter方法注入的依賴,factoryBeanName和factoryMethodName用于factorybean,也就是工廠類型的bean,initMethodName和destroyMethodName分別對應bean的init-method和destroy-method屬性。后面會對這些內容進行詳細介紹。

(2)通過BeanDefinitionRegistry將bean注冊到beanFactory中。

上面獲取到bean的信息之后,是怎么注冊到BeanFactory中的呢?其實是通過BeanDefinitionRegistry將bean注冊到beanFactory中的,因為BeanFactory的實現類需要實現BeanDefinitionRegistry接口。

BeanDefinitionRegistry接口提供了根據beanName注冊對應beanDefinition的方法。在DefaultListableBeanFactory類中實現了該方法,并將beanDefinition保存在了ConcurrentHash-Map中。

另外,Spring還對外暴露了一些接口來對bean初始化,例如BeanFactoryPostProcessor。

我們可以翻譯一下postProcessBeanFactory的注釋信息。postProcessBeanFactory可以修改應用上下文中已經進行standard初始化的beanFactory,此時所有bean的定義信息已經加載完成,但還未實例化,允許覆蓋、新增甚至重新初始化bean信息,一個典型的例子就是屬性覆蓋器PropertyOverrideConfigurer。對于一些參數,可以配置在properties中,而不用配置在Spring的XML配置文件中。

2.bean容器的實例化

上面把bean容器啟動之后,工廠算是運轉起來了,配方(beanDefinition)也已經準備充分,然后就是生產(實例化)、管理貨物(bean)了。實例化bean主要通過反射和CGLIB兩種方式,在bean的實例化過程中,Spring也暴露了一些接口,如表3-1所示。

表3-1 在bean的實例化過程中Spring暴露的一些接口

我們可以通過示例演示一下這幾個接口的使用。

(1)創建Maven project,在pom.xml中引入spring-core、spring-context。

(2)創建bean對象,實現上面列出的接口。

(3)bean配置。

(4)測試。

使用ApplicationContext獲取BeanFactory,再通過getBean方法獲取對應的bean,最后調用destroy方法進行銷毀,從輸出結果可以看到依次調用了BeanNameAware、BeanFactoryAware、InitializingBean、DisposableBean接口。

輸出結果:

3.1.3 ApplicationContext

在上面的示例中,使用ApplicationContext獲取了bean的配置,然后直接將ApplicationContext接口對象賦值給了BeanFactory接口對象,為什么可以賦值呢?其實ApplicationContext接口實現了BeanFactory接口。

public interface ApplicationContext extends EnvironmentCapable,
 ListableBeanFactory, HierarchicalBeanFactory,MessageSource,
 ApplicationEventPublisher, ResourcePatternResolver

從上面ApplicationContext接口的繼承關系可以看到,它還通過繼承其他接口擴展了BeanFactory的功能。

● MessageSource:為應用提供國際化訪問功能。

● ResourcePattern Resolver:提供資源(如URL和文件系統)的訪問支持。

● ApplicationEventPublisher:引入事件機制,包括啟動事件、關閉事件等,讓容器在上下文中提供了對應用事件的支持。它代表的是一個應用的上下文環境。

BeanFactory主要是面對Spring框架的基礎設施,面對Spring自己。Applicationcontext主要面對于Spring使用的開發者。開發者基本都會使用Applicationcontext,而非BeanFactory,所以在上面實例中使用ApplicationContext獲取BeanFactory接口對象。

上面的ApplicationContext對象是通過ClassPathXmlApplicationContext方法獲取的,還有一種獲取方式,即使用FileSystemXmlApplicationContext方法獲取。

● ClassPathXmlApplicationContext表示從類路徑下加載配置文件。文件路徑默認指的是項目的classpath路徑下,所以不需要寫前綴“classpath:”,如果指向絕對路徑,需要加上“file:”。

         new  ClassPathXmlApplicationContext(new String[]
     {"ApplicationContext.xml"});

● FileSystemXmlApplicationContext表示從文件系統中加載配置文件。文件路徑默認指的是項目的根目錄下,若想使用項目的classpath路徑,則需要加上“classpath:”。

         new  FileSystemXmlApplicationContext(new String[]{"classpath:
     ApplicationContext.xml"});
主站蜘蛛池模板: 砀山县| 汤阴县| 普洱| 杭州市| 石楼县| 理塘县| 乳山市| 灵璧县| 高陵县| 沙河市| 丰都县| 岗巴县| 宁海县| 双流县| 阿克陶县| 顺昌县| 永宁县| 兴安县| 喀喇| 界首市| 元阳县| 宁城县| 乳源| 延长县| 双流县| 浦县| 辉县市| 抚顺市| 建昌县| 葫芦岛市| 巴彦淖尔市| 望城县| 枞阳县| 巴彦淖尔市| 旺苍县| 景德镇市| 台州市| 图木舒克市| 雅安市| 金坛市| 越西县|