背景:

咱们都知道在SpringBoot发动类上添加@SpringBootApplication注解后履行main办法就可以主动发动服务 Spring会主动帮咱们找到需求办理的Bean的呢

探究:

  • 经典的八股文AbstractApplicationContext#refresh()办法 信任大家现已比较熟悉了

    从源码角度查看SpringBoot是怎样获取到Bean的

  • 进入invokeBeanFactoryPostProcessors()调用BeanFactory后置处理器办法

从源码角度查看SpringBoot是怎样获取到Bean的

  • 进入PostProcessorRegistrationDelegate的invokeBeanDefinitionRegistryPostProcessors办法 留意此办法履行后registry参数(BeanDefinitionRegistry)中的beanDefinitionMap会扫描到需求的bean信息 阐明此办法才是真实起到扫描作用的当地 重点!!!

从源码角度查看SpringBoot是怎样获取到Bean的

  • 持续进 兄弟们 往里进 ConfigurationClassPostProcessor#processConfigBeanDefinitions 两张图都是此办法 ps:代码太长 其中的这个parser.parse()便是真实解析的办法

从源码角度查看SpringBoot是怎样获取到Bean的

从源码角度查看SpringBoot是怎样获取到Bean的

  • ConfigurationClassParser#doProcessConfigurationClass到了 很近了 你要问我 我只能说 快到顶了 细心的同学应该现已看出来了 图上的这个Set会获取@ComponentScan类扫描注解 而这个入参即为咱们的发动类Class 其中发动注解@SpringBootApplication中正包含了@CompentScan这个注解 所以此时这个Set中获取到了咱们的发动类 红线标示的这个当地持续走哦

从源码角度查看SpringBoot是怎样获取到Bean的

  • componentScanAnnotationParser#parse中的scanner.doScan(StringUtils.toStringArray(basePackages)) 这里阐明一下这个basePackages因为咱们没有指定 所以默认是发动类地点的包途径 ps:这也是需求将发动类放到最外层包的原因 放里边的话无法扫描到对应Bean

从源码角度查看SpringBoot是怎样获取到Bean的

  • ClassPathBeanDefinitionScanner#doScan 持续往里 还是那句 红线标示的当地

    从源码角度查看SpringBoot是怎样获取到Bean的

  • ClassPathScanningCandidateComponentProvider#scanCandidateComponents 好了 到站 请各位乘客下车吧 这个办法便是真实找到底层bean的当地 原理很简单 参数basePackage为咱们的包根途径 即发动类地点的途径 假设为com/juejin/drink 那么此办法会递归调用扫描com/juejin/drink下的所有类和目录 如果是需求注册的bean 那么放入new的LinkedHashSet中返回

    从源码角度查看SpringBoot是怎样获取到Bean的

  • 经过如上过程 程序会返回到PostProcessorRegistrationDelegate的invokeBeanDefinitionRegistryPostProcessors办法持续履行 但此时咱们的意图达到了 实际上SpringBoot便是经过@SpringBootApplication的@CompentScan注解 拿到发动类的包途径 终究去递归调用 获取到哪些是咱们标示了@Compent这些需求注册进容器的 此过程是refresh办法的invokeBeanFactoryPostProcessors()中履行的

结语:

本文只是简单的叙述了下Spring是如何将咱们的Bean加载到beanDefinitionMap中的 比较简单 不涉及其他复杂逻辑

终究:

如发现错误 请联系作者处理 欢迎指正