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());
      }
  }

  

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