ImportBeanDefinitionRegistrar概述
概述
我们先来看看ImportBeanDefinitionRegistrar是个什么鬼,点击进入ImportBeanDefinitionRegistrar源码,如下所示。
package org.springframework.context.annotation; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.core.type.AnnotationMetadata; public interface ImportBeanDefinitionRegistrar { default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) { registerBeanDefinitions(importingClassMetadata, registry); } default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { } }
由源码可以看出,ImportBeanDefinitionRegistrar本质上是一个接口。在ImportBeanDefinitionRegistrar接口中,有一个registerBeanDefinitions()方法,通过registerBeanDefinitions()方法,我们可以向Spring容器中注册bean实例。
Spring官方在动态注册bean时,大部分套路其实是使用ImportBeanDefinitionRegistrar接口。
所有实现了该接口的类都会被ConfigurationClassPostProcessor处理,ConfigurationClassPostProcessor实现了BeanFactoryPostProcessor接口,所以ImportBeanDefinitionRegistrar中动态注册的bean是优先于依赖其的bean初始化的,也能被aop、validator等机制处理。
使用方法
ImportBeanDefinitionRegistrar需要配合@Configuration和@Import注解,@Configuration定义Java格式的Spring配置文件,@Import注解导入实现了ImportBeanDefinitionRegistrar接口的类。
ImportBeanDefinitionRegistrar实例
既然ImportBeanDefinitionRegistrar是一个接口,那我们就创建一个MyImportBeanDefinitionRegistrar类,实现ImportBeanDefinitionRegistrar接口,如下所示。
package io.mykit.spring.plugins.register.condition; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.type.AnnotationMetadata; /** * @author binghe * @version 1.0.0 * @description ImportBeanDefinitionRegistrar的实现类 */ public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /** * AnnotationMetadata: 当前类的注解信息 * BeanDefinitionRegistry:BeanDefinition注册类 * 通过调用BeanDefinitionRegistry接口的registerBeanDefinition()方法,可以将所有需要添加到容器中的bean注入到容器中。 */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry){ } }
可以看到,这里,我们先创建了MyImportBeanDefinitionRegistrar类的大体框架。接下来,我们在PersonConfig2类上的@Import注解中,添加MyImportBeanDefinitionRegistrar类,如下所示。
@Configuration @Import({Department.class, Employee.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class}) public class PersonConfig2 {
接下来,创建一个Company类,作为测试测试ImportBeanDefinitionRegistrar接口的bean,如下所示。
package io.mykit.spring.plugins.register.bean; /** * @author binghe * @version 1.0.0 * @description 测试ImportBeanDefinitionRegistrar接口的使用 */ public class Company { }
接下来,就要实现MyImportBeanDefinitionRegistrar类中的registerBeanDefinitions()方法的逻辑了,添加逻辑后的registerBeanDefinitions()方法如下所示。
/** * AnnotationMetadata: 当前类的注解信息 * BeanDefinitionRegistry:BeanDefinition注册类 * 通过调用BeanDefinitionRegistry接口的registerBeanDefinition()方法,可以将所有需要添加到容器中的bean注入到容器中。 */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry){ boolean employee = registry.containsBeanDefinition("employee"); boolean department = registry.containsBeanDefinition("department"); if (employee && department){ BeanDefinition beanDefinition = new RootBeanDefinition(Company.class); registry.registerBeanDefinition("company", beanDefinition); } }
registerBeanDefinitions()方法的实现逻辑很简单,就是判断Spring容器中是否同时存在以employee命名的bean和以department命名的bean,如果同时存在以employee命名的bean和以department命名的bean,则向Spring容器中注入一个以company命名的bean。
接下来,我们就运行SpringBeanTest类中的testAnnotationConfig7()方法来进行测试,输出结果信息如下所示。
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory personConfig2 io.mykit.spring.plugins.register.bean.Department io.mykit.spring.plugins.register.bean.Employee io.mykit.spring.plugins.register.bean.User io.mykit.spring.plugins.register.bean.Role person binghe001
可以看到,在输出结果中,并没有看到“company”,这是因为输出结果中存在io.mykit.spring.plugins.register.bean.Department和io.mykit.spring.plugins.register.bean.Employee,并不存在我们代码逻辑中的department和employee。所以,我们将registerBeanDefinitions()方法的逻辑稍微修改下,修改后的代码如下所示。
/** * AnnotationMetadata: 当前类的注解信息 * BeanDefinitionRegistry:BeanDefinition注册类 * 通过调用BeanDefinitionRegistry接口的registerBeanDefinition()方法,可以将所有需要添加到容器中的bean注入到容器中。 */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry){ boolean employee = registry.containsBeanDefinition(Employee.class.getName()); boolean department = registry.containsBeanDefinition(Department.class.getName()); if (employee && department){ BeanDefinition beanDefinition = new RootBeanDefinition(Company.class); registry.registerBeanDefinition("company", beanDefinition); } }
接下来,我们再次运行SpringBeanTest类中的testAnnotationConfig7()方法来进行测试,输出结果信息如下所示。
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory personConfig2 io.mykit.spring.plugins.register.bean.Department io.mykit.spring.plugins.register.bean.Employee io.mykit.spring.plugins.register.bean.User io.mykit.spring.plugins.register.bean.Role person binghe001 company
可以看到,此时输出了company,说明Spring容器中已经成功注册了以company命名的bean。