ImportBeanDefinitionRegistrar动态注册bean

简介

  • ImportBeanDefinitionRegistrar类只能通过其他类@Import的方式来加载,通常是启动类或配置类。
  • 使用@Import,如果括号中的类是ImportBeanDefinitionRegistrar的实现类,则会调用接口方法,将其中要注册的类注册成bean。
  • 实现该接口的类拥有注册bean的能力。

手动把一个类注册成bean

  • 首先写一个类,最终要把它注册为bean。

public class HelloService {

  }

  自定义ImportBeanDefinitionRegistrar实现类手动注册bean。

public class HelloImportBeanDefinitionRegistrar 
          implements ImportBeanDefinitionRegistrar {

      @Override
      public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
                                          BeanDefinitionRegistry registry) {
  
          //扫描注解
          Map<String, Object> annotationAttributes = importingClassMetadata
              .getAnnotationAttributes(ComponentScan.class.getName());
          String[] basePackages = (String[]) annotationAttributes.get("basePackages");
  
          //扫描类
          ClassPathBeanDefinitionScanner scanner =
                  new ClassPathBeanDefinitionScanner(registry, false);
          TypeFilter helloServiceFilter = new AssignableTypeFilter(HelloService.class);
          
          scanner.addIncludeFilter(helloServiceFilter);
          scanner.scan(basePackages);
      }
  
  }

 最后定义一个配置类发现一下上面的ImportBeanDefinitionRegistrar实现类。

 @Configuration
  @ComponentScan("com.haien.import2.domain")
  @Import(HelloImportBeanDefinitionRegistrar.class)
  public class HelloConfiguration {
  
  }

 测试:

 

@RunWith(SpringRunner.class)
  @SpringBootTest
  @ContextConfiguration(classes = {HelloConfiguration.class}) //表示只需要这一个文件
  public class DemoApplicationTest2 {
  
      @Resource
      HelloService helloService;
  
      @Test
      public void contextLoads(){
          System.out.println(helloService.getClass());
      }
  }

 

自己写一个注解实现@Component的功能

  • 目标:自己写一个注解@Mapper,配合其他类,实现被注解类可以被注册成bean的功能。

@Mapper:

  @Documented
  @Inherited
  @Retention(RetentionPolicy.RUNTIME)
  @Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER})
  public @interface Mapper {
  }

注释于类上:

  @Mapper
  public class CountryMapper {
  }

实现ImportBeanDefinitionRegistrar接口,重写registerBeanDefinitions方法,手动注册bean;同时实现一些Aware接口,以便获取Spring的一些数据。

public class MapperAutoConfiguredMyBatisRegistrar implements
          ImportBeanDefinitionRegistrar,ResourceLoaderAware,BeanFactoryAware {
      
      private ResourceLoader resourceLoader;
      private BeanFactory beanFactory;
  
      @Override
      public void registerBeanDefinitions(AnnotationMetadata annotationMetadata,
                                          BeanDefinitionRegistry registry) {
          
          MyClasssPathBeanDefinitionScanner scanner=
                  new MyClasssPathBeanDefinitionScanner(registry,false);
          scanner.setResourceLoader(resourceLoader);
          scanner.registerFilters();
          scanner.doScan("com.haien.import1.domain");
      }
  
      @Override
      public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
          this.beanFactory=beanFactory;
      }
  
      @Override
      public void setResourceLoader(ResourceLoader resourceLoader) {
          this.resourceLoader=resourceLoader;
      }
  
  }

以上我们还借助了扫描器ClassPathBeanDefinitionScanner,通过它来获取我们需要注册的bean。

  public class MyClasssPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner {

      public MyClasssPathBeanDefinitionScanner(BeanDefinitionRegistry registry,
                                               boolean useDefaultFilters) {
          super(registry, useDefaultFilters);
      }
  
      protected void registerFilters(){
          addIncludeFilter(new AnnotationTypeFilter(Mapper.class));
      }
  
      @Override
      protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
          return super.doScan(basePackages);
      }
  }

 测试:

 @RunWith(SpringRunner.class)
  @SpringBootTest(classes = MapperAutoConfig.class)
  //只将MapperAutoConfig类纳入测试环境的Spring容器中,
  //或@ContextConfiguration(classes = {MapperAutoConfig.class})
  public class DemoApplicationTest {
  
      @Resource
      CountryMapper countryMapper;
  
      @Test
      public void contextLoads(){
          System.out.println(countryMapper.getClass());
      }
  }

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章