1. 程式人生 > 實用技巧 >Spring-IOC 高階特性

Spring-IOC 高階特性

1. lazy-Init 延遲載入

  ApplicaitonContext 容器的預設行為是在啟動時將所有 singleton bean 提前進行例項化。提前例項化意味著作為初始化過程的一部分,ApplicationContext 例項會建立所有的singleton bean

開啟方式:

  • xml :<bean id="xx" class="xx.xx.xx" lazy-init="true"> (特別:可以在<beans default-lazy-init="true"></beans>來全域性配置)
  • anno:@Lazy

開啟延遲載入後,bean 將不會在ApplicationContext啟動時提前被例項化,而是在第一次向容器發起getBean呼叫索取bean時例項化

應用場景:

  1. 開啟延遲載入一定程度提高了容器啟動和運轉效能(現代裝置效能提升,影響逐漸變小)
  2. 對於不常使用的 Bean設定延遲載入,這樣偶爾使用的時候在載入,不必要從一開始該Bean 就佔用資源 (更多是基於這個考慮)

2. FactoryBean 和 BeanFactory

  BeanFactory 介面是容器的頂級介面,定義了容器的一些基礎行為,負責生產和管理Bean 的一個工廠,具體使用它下面的子介面型別,比如:ApplicationContext

  這裡重點介紹FactoryBean:Spring 中的Bean 有兩種,一種是普通 Bean ,一種是工廠 Bean(FactoryBean),FactoryBean 可以生成某一個型別的Bean例項(返回給我們),也就是說我們可以藉助於它自定義 Bean 的建立過程。

FactoryBean介面:

/**
 * 可以讓我們⾃定義Bean的建立過程(完成複雜Bean的定義)
 * @param <T>
 */
public interface FactoryBean<T> {

    /**
     * 返回FactoryBean建立的Bean例項,如果isSingleton返回true,
     * 則該例項會放到Spring容器的單例物件快取池中Map
     */
    @Nullable
    T getObject() throws Exception;

    /**
     * 返回FactoryBean建立的Bean型別
     
*/ @Nullable Class<?> getObjectType(); /** * 返回作⽤域是否單例 */ default boolean isSingleton() { return true; } }

3. 後置處理器

  Spring 提供了兩種後處理器 bean的擴充套件介面,分別為 BeanPostProcessor 和 BeanFactoryPostProcessor,兩者在使用上是有所區別的

  順序:工廠初始化 -> Bean 物件例項化

  在BeanFactory 初始化之後可以使用BeanFactoryPostProcessor 進行後置處理一些操作

  在 Bean 物件例項化(並不是Bnan的整個生命週期完成)之後可以使用BeanPostProcessor 進行後置處理做一些操作

  注: 物件不一定是springBean,而springBean一定是物件

BeanPostProcessor

  BeanPostProcessor是針對Bean 級別的處理,可以針對某個具體的Bean

  介面:

public interface BeanPostProcessor {

  /**
   * Bean 的初始化方法之前
   */ @Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; }
  /*
   * Bean 的初始化方法之後
   */ @Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } }

定義一個類實現BeanPostProcessor ,預設是會對整個spring容器中所有的bean進行處理,如果要對具體的某個bean處理,可以通過方法引數(第一個引數是bean例項,第二個引數是每個bean的id或name屬性值)判斷。

注意:處理是發生在spring容器例項化和依賴注入之後

BeanFactoryPostProcessor

  BeanFactory 級別的處理,是針對整個Bean的工廠進行處理,典型應用:

PropertyPlaceholderConfigurer。
介面:
@FunctionalInterface
public interface BeanFactoryPostProcessor {

    /**
     * 只有一個方法,引數為:ConfigurableListableBeanFactory 
     */
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}
此接⼝只提供了⼀個⽅法,⽅法引數為ConfifigurableListableBeanFactory,該引數型別定義了⼀些⽅法 其中有個方法名為:getBeanDefinition的方法,我們可以根據此方法,找到我們定義bean的BeanDefinition物件。然後我們可以對定義的屬性進行修改。 BeanDefinition物件   spring載入類物件,將類物件處理得到一個JavaBean(封裝物件資訊),這個JavaBnan 就是BeanDefinitioin物件 注意:呼叫BeanFactoryPostProcessor 方法式,這個時候bean還沒有例項化,此時bean剛被處理成BeanDefinition物件



附:spring生命週期

注:圖中6、7即對應為BeanPostProcessor 的兩個方法

過程描述:

  1)根據配置情況調⽤ Bean 構造⽅法或⼯⼚⽅法例項化 Bean。   2)利⽤依賴注⼊完成 Bean 中所有屬性值的配置注⼊。   3)如果 Bean 實現了 BeanNameAware 接⼝,則 Spring 調⽤ Bean 的 setBeanName() ⽅法傳⼊當前 Bean 的 id 值。   4)如果 Bean 實現了 BeanFactoryAware 接⼝,則 Spring 調⽤ setBeanFactory() ⽅法傳⼊當前⼯⼚例項的引⽤。   5)如果 Bean 實現了 ApplicationContextAware 接⼝,則 Spring 調⽤ setApplicationContext() ⽅法傳⼊當前 ApplicationContext 例項的引⽤。   6)如果 BeanPostProcessor 和 Bean 關聯,則 Spring 將調⽤該接⼝的預初始化⽅法postProcessBeforeInitialzation() 對 Bean 進⾏加⼯操作,此處⾮常重要,Spring 的 AOP 就是利⽤它實現的。   7)如果 Bean 實現了 InitializingBean 接⼝,則 Spring 將調⽤ afterPropertiesSet() ⽅法。   8)如果在配置⽂件中通過 init-method 屬性指定了初始化⽅法,則調⽤該初始化⽅法。   9)如果 BeanPostProcessor 和 Bean 關聯,則 Spring 將調⽤該接⼝的初始化⽅法 postProcessAfterInitialization()。此時,Bean 已經可以被應⽤系統使⽤了。   10)如果在 <bean> 中指定了該 Bean 的作⽤範圍為 scope="singleton",則將該 Bean 放⼊ Spring IoC 的快取池中,將觸發 Spring 對該 Bean 的⽣命週期管理;如果在 <bean> 中指定了該 Bean 的作⽤範圍為 scope="prototype",則將該 Bean 交給調⽤者,調⽤者管理該 Bean 的⽣命週期,Spring 不再管理該 Bean。   11)如果 Bean 實現了 DisposableBean 接⼝,則 Spring 會調⽤ destory() ⽅法將 Spring 中的 Bean 銷燬;如果在配置⽂件中通過 destory-method 屬性指定了 Bean 的銷燬⽅法,則 Spring 將調⽤該⽅法對 Bean 進⾏銷燬。 注意:Spring 為 Bean 提供了細緻全⾯的⽣命週期過程,通過實現特定的接⼝或 <bean> 的屬性設定,都可以對 Bean 的⽣命週期過程產⽣影響。雖然可以隨意配置 <bean> 的屬性,但是建議不要過多地使⽤ Bean 實現接⼝,因為這樣會導致程式碼和 Spring 的聚合過於緊密