乐趣区

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

背景:
咱们都晓得在 SpringBoot 启动类上增加 @SpringBootApplication 注解后执行 main 办法就能够主动启动服务 Spring 会主动帮咱们找到须要治理的 Bean 的呢
探索:

经典的八股文 AbstractApplicationContext#refresh()办法 置信大家曾经比拟相熟了

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

进入 PostProcessorRegistrationDelegate 的 invokeBeanDefinitionRegistryPostProcessors 办法 留神此办法执行后 registry 参数 (BeanDefinitionRegistry) 中的 beanDefinitionMap 会扫描到须要的 bean 信息 阐明此办法才是真正起到扫描作用的中央 重点!!!

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

ConfigurationClassParser#doProcessConfigurationClass 到了 很近了 你要问我 我只能说 快到顶了 认真的同学应该曾经看进去了 图上的这个 Set 会获取 @ComponentScan 类扫描注解 而这个入参即为咱们的启动类 Class 其中启动注解 @SpringBootApplication 中正蕴含了 @CompentScan 这个注解 所以此时这个 Set 中获取到了咱们的启动类 红线标注的这个中央持续走哦

componentScanAnnotationParser#parse 中的 scanner.doScan(StringUtils.toStringArray(basePackages)) 这里阐明一下这个 basePackages 因为咱们没有指定 所以默认是启动类所在的包门路 ps:这也是须要将启动类放到最外层包的起因 放外面的话无奈扫描到对应 Bean

ClassPathBeanDefinitionScanner#doScan 持续往里 还是那句 红线标注的中央

ClassPathScanningCandidateComponentProvider#scanCandidateComponents 好了 到站 请各位乘客下车吧 这个办法就是实在找到底层 bean 的中央 原理很简略 参数 basePackage 为咱们的包根门路 即启动类所在的门路 假如为 com/juejin/drink 那么此办法会递归调用扫描 com/juejin/drink 下的所有类和目录 如果是须要注册的 bean 那么放入 new 的 LinkedHashSet 中返回

通过如上步骤 程序会返回到 PostProcessorRegistrationDelegate 的 invokeBeanDefinitionRegistryPostProcessors 办法继续执行 但此时咱们的目标达到了 实际上 SpringBoot 就是通过 @SpringBootApplication 的 @CompentScan 注解 拿到启动类的包门路 最终去递归调用 获取到哪些是咱们标注了 @Compent 这些须要注册进容器的 此步骤是 refresh 办法的 invokeBeanFactoryPostProcessors()中执行的

结语:
本文只是简略的叙述了下 Spring 是如何将咱们的 Bean 加载到 beanDefinitionMap 中的 比较简单 不波及其余简单逻辑

退出移动版