天天看點

Spring Bean基礎(中)2 如何給 bean 命名?3 如何執行個體化 bean?

2 如何給 bean 命名?

每個bean都有一或多個辨別符,這些辨別符在其所在容器中必須唯一。一個bean通常隻有一個辨別符。但若它就是需要有一個以上的,那麼多餘辨別符被視為别名。

在bean定義中,可組合使用id、name 屬性指定bean的辨別符。

最多指定一個名稱的id屬性。一般來說,這些名字由字母數字組成(如myBean,fooService),但也可能包含特殊字元。

如果還想為bean引入其他别名,可在name屬性指定任意數量的其他名稱。用逗号,、分号;或空格分隔。

在Spring 3.1前,id屬性定義為xsd:ID類型,該類型限制了可能的字元。從3.1開始,它被定義為xsd:string類型。注意,Bean的id唯一性仍由容器強制執行,而不再是XML解析器。

開發者無需提供bean的name或id。如果未明确提供,容器将為該bean生成一個唯一name。但如果想通過使用ref元素或服務定位器模式查找來按名稱引用該bean,則必須提供一個name。不提供名稱的原因和内部beans和自動裝配有關。

可以為bean提供多個名稱。這些名稱視作同一bean的别名,例如允許應用中的每個元件通過使用特定于元件本身的bean名稱來引用公共依賴。

2.1 Bean命名規範

與對執行個體字段名稱的命名規範相同。即小寫字母開頭,後跟駝峰式大小寫。

示例:userService,roleController。

掃描類路徑下的元件,Spring就會按照該習慣為未命名的元件生成bean名稱:将類名初始字元轉換為小寫。其實這個規範即是JDK 裡的Introspector#decapitalize方法,Spring正使用了它:

Spring Bean基礎(中)2 如何給 bean 命名?3 如何執行個體化 bean?

decapitalize

java.beans.Introspector.decapitalize

public static String decapitalize(String name) {
    if (name == null || name.length() == 0) {
        return name;
    }
    // 如果有多個字元且第一和第二個字元均為大寫字母
    // 則會保留原始大小寫
    if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
                    Character.isUpperCase(name.charAt(0))){
        return name;
    }
    // 使用簡單的類名,并将其初始字元轉換為小寫
    char chars[] = name.toCharArray();
    chars[0] = Character.toLowerCase(chars[0]);
    return new String(chars);
}      

2.2 如何為單個bean指定多個别名?

有時希望為單個Bean提供多個名稱,尤其是在多系統環境。

XML配置

可使用

<alias/>

标簽:

<alias name="srcName" alias="extName"/>      

定義别名後,可将同一容器中名為srcName的bean稱為extName。

環境示例:

子系統A的配置中繼資料可通過名稱subA-ds引用資料源

子系統B可通過名稱subB-ds引用資料源

使用這倆子系統的主系統通過名稱main-ds引用資料源。

要使所有三個名稱都引用相同的對象,可将以下别名定義添加到配置中繼資料:

<alias name="subA-ds" alias="subB-ds"/>
<alias name="subA-ds" alias="main-ds" />      

現在,每個元件和主應用程式都可以通過唯一名稱引用資料源,并且可保證不與任何其它定義沖突(等于高效建立了名稱空間),而且引用的是同一bean。

Java代碼配置

使用

@Bean

注解的

name

屬性接收一個String數組。示例如下:

@Configuration
public class AppConfig {

    @Bean({"dataSource", "subA-ds", "subB-ds"})
    public DataSource dataSource() {
        // ...
    }
}      

3 如何執行個體化 bean?

BeanDefinition可看做是建立對象的配方。容器在被詢問時,會檢視被命名過的bean的BeanDefinition,并使用該BeanDefinition中的配置中繼資料建立(或直接從緩存池擷取)對應的對象執行個體。

比如在XML方式下,在

<bean/>

标簽的

class

屬性指定要執行個體化的對象的類型。這個

class

屬性,其實就是BeanDefinition執行個體的

Class

屬性,是以該屬性一般強制必須指定。

可通過如下方式使用

Class

屬性來執行個體化 bean:

3.1 構造器

在容器自身通過反射調用其構造器直接建立bean時,指定要構造的bean類,類似new運算符。該方式下,類基本上都能被Spring相容。即bean類無需實作任何特定接口或以特定方式編碼。 指定bean類即可。注意,根據所用的IoC類型,有時需要一個預設的無參構造器。

3.2 靜态工廠方法

指定包含将要建立對象的靜态工廠方法的實際類,容器将在類上調用靜态工廠方法以建立bean。

定義使用靜态工廠方法建立的bean時,可使用class屬性來指定包含靜态工廠方法的類,并使用factory-method屬性指定工廠方法本身的名稱。開發者應該能夠調用此方法并傳回一個存活對象,該對象随後将被視為通過構造器建立的。

這種BeanDefinition的一種用法是在老代碼中調用static工廠。

看個例子,如下BeanDefinition指定将通過調用工廠方法來建立bean。該定義不指定傳回對象的類型,而僅指定包含工廠方法的類。該示例中的

initInstance()

方法須是靜态方法。

<bean id="serverService"
    class="examples.ServerService"
    factory-method="initInstance"/>      

可與上面的BeanDefinition協同的類:

public class ServerService {
    private static ServerService serverService = new ServerService();
    private ServerService() {}

    public static ServerService createInstance() {
        return serverService;
    }
}