SpringBoot快速入门-ImportBeanDefinitionRegistrar详解

ImportBeanDefinitionRegistrar的作用是通过自定义的方式直接向容器中注册bean。
实现ImportBeanDefinitionRegistrar接口,在重写的registerBeanDefinitions方法中定义的Bean,就和使用xml中定义Bean效果是一样的。

ImportBeanDefinitionRegistrar是Spring框架提供的一种机制,允许通过api代码向容器批量注册BeanDefinition。它实现了BeanFactoryPostProcessor接口,可以在所有bean定义加载到容器之后,bean实例化之前,对bean定义进行修改。
使用ImportBeanDefinitionRegistrar,我们可以向容器中批量导入bean,而不需要在配置文件中逐个配置。

1、Xml注册Bean

我们使用xml注册bean,都是在xml文件中如下配置:

//xml定义Bean
<bean id="person4" class="com.itzhimei.handle.Person4" />

2、ImportBeanDefinitionRegistrar注册Bean

我们使用ImportBeanDefinitionRegistrar自定义注册bean的方法:

//代码定义Bean
public class ImportPerson4Reg implements ImportBeanDefinitionRegistrar

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //指定bean定义信息(包括bean的类型、作用域...)
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Person4.class);
        //注册一个bean并指定bean的id
        registry.registerBeanDefinition("person4",rootBeanDefinition);
    }
}

这里重写的方法有两个参数:AnnotationMetadata importingClassMetadata和 BeanDefinitionRegistry registry。


AnnotationMetadata importingClassMetadata参数,这个参数和ImportSelector接口对应的方法selectImports(AnnotationMetadata annotationMetadata)是一样的,作用也相同:可以使用这个方法的入参获取到@Import标注的Class的各种信息,包括其Class名称,实现的接口名称、父类名称、添加的其它注解等信息,通过这些额外的信息可以根据需要选择需要定义的Bean的Class名称。


BeanDefinitionRegistry registry参数,bean定义注册器,提供了bean注册的各种方法,Spring默认是使用的DefaultListableBeanFactory工厂类,这个工厂类实现的BeanDefinitionRegistry接口,这个类中有个Map beanDefinitionMap,Spring容器中所有注入的实例都存放在这个map中。

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

总结一下ImportBeanDefinitionRegistrar主要使用步骤:

  1. 编写一个类实现ImportBeanDefinitionRegistrar接口。
  2. 在这个类中实现registerBeanDefinitions方法。在该方法中,我们可以调用BeanDefinitionRegistry的api向容器中批量注册bean。
  3. 在配置类上使用@Import注解,将步骤1中的类导入。
  4. 该配置类是一个@Configuration类,需要在启动类上使用@Import导入该配置类。

再来看一个代码示例:

// 实现ImportBeanDefinitionRegistrar接口的类
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    // 实现registerBeanDefinitions方法
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 调用BeanDefinitionRegistry的api注册bean
        RootBeanDefinition beanDefinition = new RootBeanDefinition(MyBean.class);
        registry.registerBeanDefinition("myBean", beanDefinition);
    }
}

// 配置类,导入MyImportBeanDefinitionRegistrar
@Import({MyImportBeanDefinitionRegistrar.class})
@Configuration 
public class MyConfig { }

// 启动类,导入配置类MyConfig
@Import({MyConfig.class})
@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class, args);
    }
} 

这样,MyBean就会作为一个bean注册到Spring容器中,可以像使用其他bean一样进行注入和使用。
ImportBeanDefinitionRegistrar给我们提供了一种更灵活的向Spring容器批量注册BeanDefinition的方式。理解它有助于我们实现更复杂的自动化配置。