夯實Spring系列|第五章:Spring Bean 定義

夯實Spring系列|第五章:Spring Bean 定義

1.項目環境

2.什麼是 BeanDefinition?

什麼是 Spring Bean 的定義,或者說它是用來做什麼?
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Q9adQF7B-1587265606716)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200418150006239.png)]
Spring 應用上下文啓動時,將Xml文件、註解、API等等信息解析成 BeanDefinition 。通過依賴查找 getBean() 等方式獲取 Bean 的對象時,容器獲取到 Bean 定義相關的元信息,通過這些信息來創建對應 Bean 對象。

BeanDefinition 是 Spring FrameWork 中定義 Bean 的配置元信息接口

  • Bean 的類名
  • Bean 行爲配置元素,如作用域、自動綁定模式、生命週期回調等等
  • 其他Bean引用,又可稱作 合作者(Collaborators)或者 依賴(Dependencies)
  • 配置設置,比如Bean屬性(Properties)

3.BeanDefinition 元信息

屬性(Property) 說明
Class Bean 全類名,必須是具體類,不能用抽象類或者接口
Name Bean 的名稱或者 ID
Scope Bean 的作用域(singleton、prototype等)
Constructor arguments Bean 構造器參數(用於依賴注入)
Properties Bean 屬性設置(用於依賴注入)
Autowiring mode Bean 自動綁定模式(通過名稱 byName)
Lazy initalization mode Bean 延遲初始化模式(延遲和非延遲)
Initalization method Bean 初始化回調方法名稱
Destruction method Bean 銷燬回調方法名稱

4.BeanDefinition 構建

  • 通過 BeanDefinitionBuiler
  • 通過 AbstractBeanDefinition 以及派生類

示例:

/**
 * {@link org.springframework.beans.factory.config.BeanDefinition} 構建示例
 */
public class BeanDefinitionCreationDemo {
    public static void main(String[] args) {
        //1.通過 BeanDefinitionBuilder
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
        //通過屬性設置
        beanDefinitionBuilder.addPropertyValue("age", 18)
                .addPropertyValue("id", 1L)
                .addPropertyValue("name", "xwf");
        // 獲取 BeanDefinition 對象
        AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        // beanDefinition 並非 Bean 的終態 可以自定義修改

        //2.通過 AbstractBeanDefinition 以及派生類
        GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
        genericBeanDefinition.setBeanClass(User.class);
        //通過屬性設置
        MutablePropertyValues propertyValues = new MutablePropertyValues();
//        propertyValues.addPropertyValue("age", 18);
//        propertyValues.addPropertyValue("id", 1L);
//        propertyValues.addPropertyValue("name", "xwf");dependency-lookup-context.xml
        propertyValues.add("age", 18)
                .add("id", 1L)
                .add("name", "xwf");
        genericBeanDefinition.setPropertyValues(propertyValues);
    }
}

其實通過 API 來定義和 XML 文件配置可以類比
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-BtX0CjSz-1587265606718)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200418152630999.png)]

5.Spring Bean 的命名

5.1 Bean 名稱

可以類比 xml配置文件<bean …>的 id、name 屬性。

  • 每個 Bean 擁有一個或者多個標識符(identifiers),這些標識符在 Bean 所在的容器必須是唯一的。通常一個 Bean 僅有一個標識符,如果需要額外的,可考慮使用別名(Alias)來擴充
  • 在基於 XML 的配置元信息中,開發人員可用 id 或者 name 屬性來規定 Bean 的標識符。通常 Bean 的標識符由字母組成,允許出現特殊字符;如果想要引入 Bean 的別名的話,可以在 name 屬性使用半角逗號(,)或者分好(;)來間隔。
  • Bean 的 id 或者 name 屬性並非必須制定,如果留空的話,容器會爲 Bean 自動生成一個唯一的名稱。Bean 的命名儘管沒有限制,不過官方建議採用駝峯的方式,更符合 Java 命名規範。

5.2 Bean名稱生成器

  • org.springframework.beans.factory.support.BeanNameGenerator#generateBeanName(since Spring 2.0.3)
    • DefaultBeanNameGenerator
    • AnnotationBeanNameGenerator

我們可以看下其中一個實現

	public static String generateBeanName(
			BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean)
			throws BeanDefinitionStoreException {

		String generatedBeanName = definition.getBeanClassName();
	...
		String id = generatedBeanName;
		if (isInnerBean) {//如果是內嵌的 BeanName +'#'+ hashCode
			// Inner bean: generate identity hashcode suffix.
			id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition);
		}
		else {//如果是唯一的
			// BeanName +'#'+ 數字
			return uniqueBeanName(generatedBeanName, registry);
		}
		return id;
	}

6.Spring Bean 的別名

Bean 別名(Alias)的價值

  • 複用現有的 BeanDefinition
  • 更具有場景化的命名方法

示例

新建一個 bean-definitions-context.xml 文件,import之前的 xml 文件,爲 user 取一個別名。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <import resource="classpath:/META-INF/dependency-lookup-context.xml"/>
    <!-- 將 Spring 容器中的 user Bean 關聯/建立別名 -->
    <alias name="user" alias="xwf-user"/>

</beans>

BeanAlisaDemo

/**
 * Bean 別名示例
 */
public class BeanAlisaDemo {
    public static void main(String[] args) {
        //配置 xml 配置文件
        //啓動 spring 應用上下文
        BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-definitions-context.xml");
        User xwfUser = (User) beanFactory.getBean("xwf-user");
        User user = (User) beanFactory.getBean("user");
        System.out.println(xwfUser==user);
    }
}

輸出結果爲 true,說明不管是通過名稱還是別名取到的都是同一個對象,說明 spring 容器底層在初始化的時候對名稱和別名做了相應的映射。

7.參考

  • 極客時間-小馬哥《小馬哥講Spring核心編程思想》
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章