What is BeanDefinition

BeanDefinition的元信息

BeanDefinition:Spring framework中定义Bean的配置元信息,包含关于Bean的众多信息。
Spring通过扫描配置信息,得到BeanDefinition信息,再通过BeanDefinition创建Bean

属性 说明 对应的方法
Class Name Bean的全限定类名,必须是具体类,不可以使用接口或抽象类 #setBeanClassName(@Nullable String beanClassName)
name Bean的名称或ID,Bean名在当前容器中唯一,如果没有显示设置,则会生成默认的Bean名 DefaultBeanNameGeneratorAnnotationBeanNameGenerator
Scope 作用域:singleton,prototype
Constructor Arguments BeanDefinition#getConstructorArgumentValues和子类的AbstractBeanDefinition#setConstructorArgumentValues(ConstructorArgumentValues constructorArgumentValues) 构造器参数,记录顺序,不记录名称
Autowiring mode 自动绑定模式:byName或byType #setAutowireCandidate(boolean autowireCandidate
Lazy Initialization Mode 延迟初始化方式 #setInitMethodName(@Nullable String initMethodName)
Initialization Method 初始化回调函数 #setInitMethodName(@Nullable String initMethodName)
Destruction Method 销毁回调函数 #setDestroyMethodName(@Nullable String destroyMethodName)
DependsOn 其他Bean引用 #setDependsOn(@Nullable String... dependsOn)
Property 属性配置 BeanDefinition#getPropertyValues()和子类的AbstractBeanDefinition#setPropertyValues(MutablePropertyValues propertyValues)

(为了排版,Constructor Arguments行的列描述换位撑开中间宽度…)

如何构建BeanDefinition

  • 通过BeanDefinitionBuild
  • 通过AbstractBeanBeanDefinition以及派生类
    public static void main(String[] args) {
        // 1.通过 BeanDefinitionBuilder 构建
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
        beanDefinitionBuilder
                .addPropertyValue("id", 18)
                .addPropertyValue("name", "asteroid");
        BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        // BeanDefinition 并非 Bean 终态,可以自定义修改
        // 2. 通过 AbstractBeanDefinition 以及派生类
        GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
        genericBeanDefinition.setBeanClass(User.class);
        MutablePropertyValues propertyValues = new MutablePropertyValues();
        propertyValues
                .add("id", 18)
                .add("name", "asteroid");
        genericBeanDefinition.setPropertyValues(propertyValues);
    }

name and alias

name

  • Bean名在当前容器中唯一
  • 如果没有显示设置,则会生成默认的Bean名
  • DefaultBeanNameGeneratorAnnotationBeanNameGenerator生成默认名

alias

  • alias可以有多个
  • 使同一个bean可以在不同场景中更好的调用

未完待续…

How to register

如何将Bean注册入容器中?

  • XML配置:
  • Java注解配置:
    1. @Bean:最常用的,被扫描后,自动注册进容器
    2. @Component:直接类上增加@Component
    3. @Import:启动类上增加注解@Import(ImportBean.class)
// 3. 通过 @Import 来进行导入
@Import(AnnotationRegistryBean.Config.class)
public class AnnotationRegistryBean {

    public static void main(String[] args) {
        // 创建 BeanFactory 容器,注册 Configuration Class(配置类)
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(AnnotationRegistryBean.class);

        // 1.命名 Bean 的注册方式和非命名 Bean 的注册方法
        registerUserBeanDefinition(applicationContext, "asteroid");
        registerUserBeanDefinition(applicationContext);

        applicationContext.refresh();
        System.out.println("Config 类型的所有 Beans" + applicationContext.getBeansOfType(Config.class));
        System.out.println("User 类型的所有 Beans" + applicationContext.getBeansOfType(User.class));
        //打印时不会出现别名,因为Alisa只是辅助作用,而不是真正的Bean名称,Alisa在另一个地方管理
        applicationContext.close();
    }

    public static void registerUserBeanDefinition(BeanDefinitionRegistry registry) {
        registerUserBeanDefinition(registry, null);
    }

    public static void registerUserBeanDefinition(BeanDefinitionRegistry registry, String beanName) {
        BeanDefinitionBuilder beanDefinitionBuilder = genericBeanDefinition(User.class);
        beanDefinitionBuilder
                .addPropertyValue("id", 18)
                .addPropertyValue("name", "asteroid");

        if (StringUtils.hasText(beanName)) {
            // 注册 BeanDefinition
            registry.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition());
        } else {
            // 非命名 Bean 注册方法
            BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinitionBuilder.getBeanDefinition(), registry);
        }
    }

    // 2. 通过 @Component 方式定义当前类作为 Spring Bean(组件)
    @Component 
    public static class Config {
        /**
         * 1. 通过 @Bean 方式定义
         * 通过 Java 注解的方式,定义了一个 Bean
         */
        @Bean(name = {"user"})
        public User user() {
            User user = new User();
            user.setId(18);
            user.setName("asteroid");
            return user;
        }
    }
}

  • JavaAPI配置:
方式 方法
命名方式 BeanDefinitionRegistry#registerBeanDefination
非命名方式 BeanDefinitionReaderUtils#registerWithGeneratedName

实现略…

instantiation - 实例化

BeanDefinition已生成,依赖注入时触发实例化。
实例化的方式有哪些?
常规方式

  • 通过构造器:new
  • 通过静态工厂方法:比如XML中bean标签的factory-method属性指定静态工厂方法
  • 通过Bean工厂方法:比如定义一个UserFactory类和内部的一个createUser()非静态方法;然后在XML中定义一个bean标签并指定其属性factory-beanfactory-method分别为前工厂的对应类和方法名。
  • 通过FactoryBean:定义一个UserFactoryBean并实现FactoryBean接口并实现其getObject()方法和getObjectType()方法。然后直接再XML中定义bean标签其class属性就是UserFactoryBean全限定名称即可。
   <!-- 静态方法实例化 Bean -->
<bean id="by-static-method" class="org.domain.User" factory-method="createUser"/>

   <!-- Bean工厂方法实例化 Bean ,1、定义工厂,2、通过bean工厂的方法实例化Bean-->
<bean id="userFactory" class="org.factory.DefaultUserFactory"/>
<bean id="by-instance-method" factory-bean="userFactory" factory-method="createUser"/>

   <!-- FactoryBean实例化 Bean -->
<bean id="by-factory-bean" class="org.factory.UserFactoryBean" />
    public static void main(String[] args) {
        //读取配置文件,并通过依赖查找获取Bean
        BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/bean.xml");
        User user = beanFactory.getBean("by-static-method", User.class);
        User userByInstanceMethod = beanFactory.getBean("by-instance-method", User.class);
        User userByFactoryBean = beanFactory.getBean("by-factory-bean", User.class);
        
        System.out.println(user);
        System.out.println(userByInstanceMethod);
        System.out.println(userByFactoryBean);

        System.out.println(user == userByInstanceMethod);
        System.out.println(user == userByFactoryBean);
        System.out.println(userByFactoryBean == userByInstanceMethod);
        //从不同渠道产生的Bean,所以输出3个false

    }

特殊方式

  • ServiceLoadFactoryBean:在classpath的META-INF/servives下创建一个文件,名称是某接口的全限定名称,文件无后缀。文件中直接写上接口实现类的全限定名。然后使用ServiceLoader相关的api即可实现接口实现类的实例化。
  • AutowireCapableFactory#createBean:注意class参数不能是接口或者抽象类,否则不能初始化
  • BeanDefinitionRegistry#registBeanDefinition:

实现略…

initialization - 初始化

非延迟初始化

  • @PostConstruct
  • 实现InitializingBean接口,重写#afterPropertiesSet方法
  • 自定义初始化方法
    1. Xml:
    2. Java注解:@Bean(initMethod=“doInit”)
    3. Java API:AbstractBeanDefinition#setInitMethodName
public class InitializationDemo implements InitializingBean {
    @PostConstruct
    public void init() {
        System.out.println("@PostConstruct : InitializationDemo 初始化中...");
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean#afterPropertiesSet() : InitializationDemo 初始化中...");
    }
    public void doInit() {
        System.out.println("自定义初始化方法 doInit() : InitializationDemo 初始化中...");
    }
}

执行顺序:@PostConstruct > InitializingBean#afterPropertiesSet > 自定义初始化方法

延迟初始化

使用方式

  • XML:
  • 注解:@Lazy

一点归纳

  • 可以解决一定情况下的依赖冲突(有解决方法不代表可以出现依赖冲突,出现依赖冲突说明代码设计有误)
  • 会在获取调用#getBean时才初始化,使用上与非延迟Bean无异
  • spring的#refresh方法,会显示调用初始化Bean方法,并注明初始化非延迟加载的
  • 定义BeanDefinition上没有过多不通过,区别再与依赖查找和依赖注入时的一点细微不同

destroy

在Bean销毁、应用上下文关闭ApplicationContext#close时回调的方法,容器会调用所有单例Bean的销毁方法

  • @PreDestroy
  • 实现DisposableBean接口的destroy方法
  • 自定义销毁方法:
    1. XML:
    2. @Bean(destro=“doDestroy”)
    3. AbstractBeanDefinition# setDestroyMethodName
public class DestoryBeanDemo implements DisposableBean {
    @PreDestroy
    public void preDestroy() {
        System.out.println("@PreDestroy : DestoryBeanDemo 销毁中...");
    }
    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean#destroy : DestoryBeanDemo 销毁中...");
    }
    public void doDestroy() {
        System.out.println("自定义销毁方法 doDestroy : DestoryBeanDemo 销毁中...");
    }

}

执行顺序:@PreDestroy > DisposableBean#destroy > 自定义

未完待续…(BeanDefinition#ParentName,BeanDefinition#Role)

文章作者: Administrator
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 AE86小行星
编程之路 Spring Java
喜欢就支持一下吧