文章内容
一、简介
- ImportBeanDefinitionRegistrar类只能通过其他类@Import的方式来加载,通常是启动类或配置类。
- 使用@Import,如果括号中的类是ImportBeanDefinitionRegistrar的实现类,则会调用接口方法,将其中要注册的类注册成bean。
- 实现该接口的类拥有注册bean的能力。
二、手动把一个类注册成bean
1、首先写一个类,最终要把它注册为bean。
1 2 3 | public class HelloService { } |
2、自定义ImportBeanDefinitionRegistrar实现类手动注册bean。
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 | public class HelloImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /** * @Description AnnotationMetadata:当前类的注解信息; * BeanDefinitionRegistry:注册类,其registerBeanDefinition()可以注册bean **/ @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); } } |
3、最后定义一个配置类发现一下上面的ImportBeanDefinitionRegistrar实现类。
1 2 3 4 5 6 | @Configuration @ComponentScan ( "com.ntan520.test" ) @Import (HelloImportBeanDefinitionRegistrar. class ) public class HelloConfiguration { } |
4、测试
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | @RunWith (SpringRunner. class ) @SpringBootTest @ContextConfiguration (classes = {HelloConfiguration. class }) //表示只需要这一个文件 public class DemoApplicationTest { @Resource HelloService helloService; /** * @Description 扫描到helloService **/ @Test public void contextLoads() { System.out.println(helloService.getClass()); } } |
三、自定义注解实现@Component的功能
1、需求
自定义一个注解@Mapper,配合其他类,实现被注解类可以被注册成bean的功能。
2、@Mapper注解定义
1 2 3 4 5 6 7 | @Documented @Inherited @Retention (RetentionPolicy.RUNTIME) @Target ({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) public @interface Mapper { } |
3、注解使用
注释于类上:
1 2 3 | @Mapper public class TestMapper { } |
4、注册类定义
实现ImportBeanDefinitionRegistrar接口,重写registerBeanDefinitions方法,手动注册bean;同时实现一些Aware接口,以便获取Spring的一些数据。
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | public class MapperAutoConfiguredMyBatisRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, BeanFactoryAware { private ResourceLoader resourceLoader; private BeanFactory beanFactory; /** * @Description 注册bean,但不知道需要注册哪些bean,所以需要借助 * ClassPathBeanDefinitionScanner扫描器,扫描需要注册的bean **/ @Override public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) { MyClasssPathBeanDefinitionScanner scanner = new MyClasssPathBeanDefinitionScanner(registry, false ); scanner.setResourceLoader(resourceLoader); scanner.registerFilters(); scanner.doScan( "com.ntan520.test" ); } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this .beanFactory=beanFactory; } @Override public void setResourceLoader(ResourceLoader resourceLoader) { this .resourceLoader = resourceLoader; } } |
5、扫描器定义
定义扫描器ClassPathBeanDefinitionScanner,通过它来获取需要注册的bean。
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 | public class MyClasssPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner { public MyClasssPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) { super (registry, useDefaultFilters); } /** * @Description 注册条件过滤器,将@Mapper注解加入允许扫描的过滤器中, * 如果加入排除扫描的过滤器集合excludeFilter中,则不会扫描 **/ protected void registerFilters() { addIncludeFilter( new AnnotationTypeFilter(Mapper. class )); } @Override protected Set<BeanDefinitionHolder> doScan(String... basePackages) { return super .doScan(basePackages); } } |
6、测试
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | /** * 只将MapperAutoConfig类纳入测试环境的Spring容器中, * 或@ContextConfiguration(classes = {MapperAutoConfig.class}) */ @RunWith (SpringRunner. class ) @SpringBootTest (classes = MapperAutoConfig. class ) public class DemoApplicationTest { @Resource TestMapper testMapper; @Test public void contextLoads() { System.out.println(testMapper.getClass()); } } |