夯实Spring系列|第五章:Spring Bean 定义

文章目录

  • 夯实Spring系列|第五章:Spring Bean 定义
    • 1.项目环境
    • 2.什么是 BeanDefinition?
    • 3.BeanDefinition 元信息
    • 4.BeanDefinition 构建
    • 5.Spring Bean 的命名
      • 5.1 Bean 名称
      • 5.2 Bean名称生成器
    • 6.Spring Bean 的别名
    • 7.参考

夯实Spring系列|第五章:Spring Bean 定义

1.项目环境

  • jdk 1.8
  • spring 5.2.2.RELEASE
  • github 地址:https://github.com/huajiexiewenfeng/thinking-in-spring
    • 本章模块:spring-bean

2.什么是 BeanDefinition?

什么是 Spring Bean 的定义,或者说它是用来做什么?
夯实Spring系列|第五章:Spring Bean 定义_第1张图片
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 文件配置可以类比
夯实Spring系列|第五章:Spring Bean 定义_第2张图片

5.Spring Bean 的命名

5.1 Bean 名称

可以类比 xml配置文件的 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 取一个别名。


<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"/>
    
    <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核心编程思想》

你可能感兴趣的:(Spring系列)