閱讀887 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Spring IoC 學習(2)

前言

知道了IoC的好處和優勢之後,本來應該有的一步是,搞清楚怎麼用。因為前麵我寫的順序是:是什麼,為什麼?下一個part肯定的就是怎麼辦或者怎麼用?但是,按照Spring的官方的Guide,我覺得應該大家是可以寫個Hello World。網上這類的教程也很多,加上其實我這次學習Spring是想更加深入的學習,因此,重點就不放在這個部分了。主要放在學習背後的故事。

這小節的內容就是學習IoC的容器。

兩種容器

概述

整個IoC容器可以分為兩個階段,容器啟動階段和實例化階段。

image.png | center | 390x261

容器啟動階段

①就是把xml文件裏麵的配置信息弄到BeanDefinition中。那就必須來看一下BeanDefinition

private volatile Object beanClass;
private String scope;
private boolean abstractFlag;
private boolean lazyInit;
private int autowireMode;
private int dependencyCheck;
private String[] dependsOn;
...

這個裏麵的東西也是相當的多,但是總的來說就是記錄一些bean的信息,方便與後麵的實例化。

② 讀完配置文件之後,是得到了很多BeanDefinition。然後通過BeanDefinitionRegistry將這些bean注冊到beanFactory中。下麵看一看具體的實現類DefaultListableBeanFactory裏麵是如何注冊的。

/** Map of bean definition objects, keyed by bean name */
    private final Map<String, BeanDefinition> beanDefinitionMap 
                                    = new ConcurrentHashMap<String, BeanDefinition>(64);
//... codes ...

//---------------------------------------------------------------------
// Implementation of BeanDefinitionRegistry interface
//---------------------------------------------------------------------
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {
// ...codes...
            this.beanDefinitionMap.put(beanName, beanDefinition);

// ...codes...

上麵的代碼雖然省略了很多很多的邏輯,但是實際重要的部分是我體現的那部分,首先,DefaultListableBeanFactory中先是new了一個final的ConcurrentHashMap,用來裝BeanDefinition,然後經過一係列的邏輯判斷之後,裝進去。後麵如果要拿出來,想著應該也是用相應的方法拿出來。

不信你看

@Override
public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
    BeanDefinition bd = this.beanDefinitionMap.get(beanName);
    if (bd == null) {
        if (this.logger.isTraceEnabled()) {
            this.logger.trace("No bean named '" + beanName + "' found in " + this);
        }
        throw new NoSuchBeanDefinitionException(beanName);
    }
    return bd;
}

到了這一步,按理,我們的第一步,即容器啟動階段就結束了。然而
image.png | center | 180x216

Spring還給我們提供了接口,幹什麼呢?如果你想搞些事情呢?那我不能讓你搞,豈不是很不好。開源框架嘛,拓展性非常重要。

接口--BeanFactoryPostProcessor就是做這個工作的,其中有幾個Spring自帶的,挺有用的BeanFactoryPostProcessor。

① PropertyPlaceHolderConfigurer
diagram.svg | center | 952x400

從這個類圖上就可以看到,PropertyPlaceholderConfigurer間接實現了BeanFactoryPostprocessor。是Spring自帶的搞事情實現類。

【主要功能】

為什麼叫PropertyPlaceHolderConfigurer,PlaceHolder就叫做占位符,所以這個Configurer主要的功能特點,就是占位符相關的。例如,以下我們這種常見的應用。

image.png | left | 265x172

很常見吧,我們不直接寫值,而是寫占位符,然後在其他地方我們再去寫值。當然,要用它,必須要把它加上

image.png | center | 651x200

② PropertyOverrideConfigurer

diagram啊啊.svg | center | 671x318

以下代碼說明應用

<bean class ="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
<property name="properties">
<map>
    <!-- 不管原來的sex是什麼,最後就是male -->
    <entry key="testBean.sex" value="male"/>
</map>
</property>

可以用來覆蓋原來初始化的值。不過其實我有一個問題,為什麼要多此一舉。要不就是隻有一種可能,那個配置文件,我們沒法改,那我們就在這個地方做一個修改。這麼想想的話,還是有些作用的。

③ CustomEditorConfigurer

這家夥的中文名叫自定義屬性編輯器,又一個中文字麵全看懂,不知道幹啥用的典例。
image.png | center | 166x220

Class Person{
    Date birthday;
    // setter getter 等默認有【懶】
}

beans.xml

<!-- 實例化直接是個String,人家怎麼知道你是不是Date,怎麼知道怎麼轉換 -->
<bean  >  
      <property name="birthday">  
         <value>2017-08-29</value>  
    </property>  
</bean>  
<!-- 定義屬性編輯器 -->        
<bean  >  
    <property name="customEditors">  
        <map>  
            <entry key="java.util.Date">  
                <bean >  
                    <property name="format" value="yyyy-MM-dd"/>  
                </bean>  
            </entry>  
        </map>  
    </property>  
</bean> 

自己定義的日期類型編輯器

import java.beans.PropertyEditorSupport;  
import java.text.ParseException;  
import java.text.SimpleDateFormat;  
import java.util.Date;  

/** 
 * java.util.Date屬性編輯器  
 * @author Administrator 
 * 
 */  
public class UtilDatePropertyEditor extends PropertyEditorSupport {  

    private String format="yyyy-MM-dd";  

    @Override  
    public void setAsText(String text) throws IllegalArgumentException {  
        SimpleDateFormat sdf = new SimpleDateFormat(format);  
        try {  
            Date d = sdf.parse(text);  
            this.setValue(d);  
        } catch (ParseException e) {  
            e.printStackTrace();  
        }  
    }  

    public void setFormat(String format) {  
        this.format = format;  
    }  

}  

Bean實例化階段

  本來是要把Bean實例化階段也寫完的,但是鑒於現在為止,整個的篇幅已經比較長,再寫下去,怕是有人要煩了。【我才不會說是我累了】

image.png | center | 255x255

最後更新:2017-08-29 18:03:18

  上一篇:go  【線下技術沙龍】阿裏專家DevOps玩法全揭秘,加速開發運維一體化
  下一篇:go  電話語音唿叫係統如何幫助企業迅速提高銷售轉化 米領通信