小言_互联网的博客

SpringBoot源码学习(十四)- 动态bean注册

597人阅读  评论(0)

在看源码的时候,我们发现了一个接口ImportBeanDefinitionRegistrar,当时只是简单的了解了一下spring的大概,没有做复习。在我们开始学习mybatis源码的时候,发现这个接口成为我们必要学习的东西。那么这个接口是做什么的,还有就是这个接口的原理是什么。怀着疑问,让我们学习一下吧!

首先我们还是不去直接看原理,我们还是先根据网上资料实践一下这个接口的功能。根据资料,该接口的主要作用就是用来动态的注入bean到spring ioc中。但是问题是什么是动态,或者怎么样的操作才算是动态。难道以前都不算动态吗。作者对这里的动态的理解是可以用户自定义的决定注入哪些类。这里的自定义就是规则。根据作者的实践,认为就是注入作者自定义的注解的bean到ioc容器中。那么如何实现一个自定义的动态注入器。这里我们就实践一下。

       1.自定义定义注解(相当于打个标志,让spring扫描的时候进行识别)


   
  1. @Documented
  2. @Inherited
  3. @Retention(RetentionPolicy.RUNTIME)
  4. @Target({ ElementType .TYPE, ElementType .FIELD, ElementType .METHOD, ElementType .PARAMETER})
  5. public @interface TianMapper {
  6. }

2.定义要注入的类(该类被自定义注解修饰


   
  1. @TianMapper
  2. @Data
  3. public class TianConfig {
  4. public String toString(){
  5. return this.getClass()+ "TianConfig";
  6. }
  7. })

3.自定义扫描器(自定义扫描的包和限制被扫描的类的标志等)


   
  1. @Data
  2. public  class TianClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
  3.      private Class annotationClass;
  4.     
  5. public TianClassPathMapperScanner(BeanDefinitionRegistry registry) {
  6. super(registry);
  7.     }
  8. }

4.实现ImportBeanDefinitionRegistrar接口,在spring启动时候扫描自定义注解的类


   
  1. public class TianImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, BeanFactoryAware {
  2. private ResourceLoader resourceLoader;
  3. private BeanFactory beanFactory;
  4. @Override
  5. public void setResourceLoader(ResourceLoader resourceLoader) {
  6. this.resourceLoader = resourceLoader;
  7. }
  8. @Override
  9. public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
  10. TianClassPathMapperScanner tianClassPathMapperScanner= new TianClassPathMapperScanner(registry);
  11. //设置基本的注解
  12. tianClassPathMapperScanner.setAnnotationClass(TianMapper.class);
  13. //设置运行被扫描的注解
  14. tianClassPathMapperScanner.addIncludeFilter( new AnnotationTypeFilter(TianMapper.class));
  15.          //设置需要进行扫描的包
  16. tianClassPathMapperScanner.scan("com.scaffold.simple.admin.springtest");
  17. }
  18. @Override
  19. public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
  20. this.beanFactory = beanFactory;
  21. }
  22. }

5.将需要被spring启动执行的接口加入到ioc中。

@Import(TianImportBeanDefinitionRegistrar.class)

运行源代码,发现我们的TianConfig已经注入进去了。

通过上述的学习,我们就大概知道该接口就是对spring类扫描规范的一种扩展,可以让我们开发人员自定义注解然后交由ioc容器进行管理。其实这种用法在一些第三方包中应用的非常广泛。比如开始的时候说的mybatis。

二,实现的原理

作者通过代码跟踪,最后发现最终调用的访问如下:

在invokeBeanFactoryPostProcessors(beanFactory);方法中,

最终的调用实现是for循环实现。


   
  1. private void loadBeanDefinitionsFromRegistrars(Mapregistrars) {
  2. registrars.forEach((registrar, metadata) ->
  3. registrar.registerBeanDefinitions(metadata, this.registry));
  4. }

总结:spring在invokeBeanFactoryPostProcessors方法对类进行类级别注解解析扫描的时候,顺便就将ImportBeanDefinitionRegistrar接口的实现类标记出来。并进行全部解析然后转化成初级的beandefine,并在最后的onfresh过程中真正的实例化。


转载:https://blog.csdn.net/tianjingle_blog/article/details/111466045
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场