一、是什么?
查看接口注釋:根據給定的注釋元數據,根據需要注冊bean定義......spring會遍歷所有的beanDefinition,逐個創建對應的bean。
public interface ImportBeanDefinitionRegistrar {
/**
* Register bean definitions as necessary based on the given annotation metadata of
* the importing {@code @Configuration} class.......(截取部分注釋)
*/
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
BeanNameGenerator importBeanNameGenerator) {
registerBeanDefinitions(importingClassMetadata, registry);
}
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
}
}
PS:創建bean還有哪些方式?
1、@Component、@Bean等等
2、@Import(導入類)
3、實現ImportSelector接口,重寫selectImports方法,返回需要導入的全類名
4、實現ImportBeanDefinitionRegistrar接口,注冊bean定義
二、demo案例
StudentBean:學生類
public class StudentBean {
private String stuName;
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
}
StudentImportBeanDefinitionRegistrar:實現ImportBeanDefinitionRegistrar接口
@Component
public class StudentImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 創建beanDefinitionBuilder
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(StudentBean.class);
beanDefinitionBuilder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
// 獲取beanDefinition
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
BeanDefinitionHolder beanDefinitionHolder = new BeanDefinitionHolder(beanDefinition, StudentBean.class.getSimpleName());
// 注冊beanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(beanDefinitionHolder, registry);
}
}
啟動類:使用@Import導入
StudentImportBeanDefinitionRegistrar類
@Import(StudentImportBeanDefinitionRegistrar.class)
@SpringBootApplication
public class DemoApplication {
public static void mAIn(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(DemoApplication.class, args);
StudentBean studentBean = applicationContext.getBean(StudentBean.class);
System.out.println("studentBean: " + studentBean);
}
}
我們大都習慣使用@Enable***方式引入某個組件,此處可稍作改造。
新增注解:EnableStudentBean
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(StudentImportBeanDefinitionRegistrar.class)
public @interface EnableStudentBean {
}
啟動類修改:
@EnableStudentBean
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(DemoApplication.class, args);
StudentBean studentBean = applicationContext.getBean(StudentBean.class);
System.out.println("studentBean: " + studentBean);
}
}
三、ImportBeanDefinitionRegistrar在其他開源項目中的使用
- MyBatis
在使用mybatis時,我們需要指定mapper的掃描路徑:
@MapperScan(basePackages = "com.test.demo.dao.mapper")
查看@MapperScan源碼,發現導入了MapperScannerRegistrar類,該類實現了
ImportBeanDefinitionRegistrar接口
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan
MapperScannerRegistrar類(截取部分代碼):
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 獲取MapperScan注解
AnnotationAttributes mapperScanAttrs = AnnotationAttributes
.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
if (mapperScanAttrs != null) {
// 掃描對應的mapper接口,并注冊BeanDefinition(bean定義)
registerBeanDefinitions(importingClassMetadata, mapperScanAttrs, registry,
generateBaseBeanName(importingClassMetadata, 0));
}
}
}
- Openfeign
在使用OpenFeign時,我們需要指定feign接口掃描路徑:
@EnableFeignClients(basePackages = ""com.test.demo")
查看@EnableFeignClients源碼,發現導入了FeignClientsRegistrar類,該類實現了
ImportBeanDefinitionRegistrar接口
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients
FeignClientsRegistrar類(截取部分代碼):
class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,BeanDefinitionRegistry registry) {
registerDefaultConfiguration(metadata, registry);
registerFeignClients(metadata, registry);
}
}
掃描所有加了@FeignClient注解的接口,接著注冊FeignClientFactoryBean類型的BeanDefinition到容器中,需要使用時生成具體的接口代理實現服務調用。