通过在org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition这个方法打断点可以知晓所有的注册途径
xml注册bean
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/note/simpleApplication.xml");
assertThat(ctx.containsBean("noteFirst")).isTrue();
assertThat(ctx.containsBean("noteBean")).isTrue();ctx.close();

需要在配置文件中指定bean或者指定扫描的包
<bean id="noteFirst" name="noteFirst"
class="org.springframework.note.NoteFirst"/>
<context:component-scan base-package="org.springframework.note"></context:component-scan>
在refresh方法的obtainFreshBeanFactory->refreshBeanFactory->loadBeanDefinitions处理beanDefinition
对于bean的处理,最终是在org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#processBeanDefinition这个方法处理的
对于context:component-scan,则会走到org.springframework.context.annotation.ComponentScanBeanDefinitionParser#parse,通过scan扫描到@Component、@ManagedBean、@Named的bean,通过org.springframework.beans.factory.support.BeanDefinitionReaderUtils#registerBeanDefinition方法注册
注解注册
@Component
所有的@Component标注的类需要被扫描到才可以,不然不会加载,因此,也可以确定@Component标注的类是通过doScan来处理的
对于这种的bean是需要通过beanDefinition的后处理器来加载bean,也就是refresh的invokeBeanFactoryPostProcessors方法


这里的ConfigurationClassPostProcessor是通过内部注册到beanFactory的
会调用ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry->org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions

如图,postProcessBeanDefinitionRegistry方法中处理ComponentBean的地方是在ConfigurationClassParser.parse,其最终执行的是ConfigurationClassParser#doProcessConfigurationClass
但candidates必须有值,也就是说为了扫描别的bean,至少有一个bean已经注册且已经指定了ComponentScan的范围,一般来说如果是AnnotationConfigApplicationContext,那就是启动时指定的类

而如果是springboot,那就是@SpringBootApplication标注的类
最终会在下面这段代码扫描所有的Component

@Bean
@Bean是在加载@Component的bean之后进行处理的,虽然在bean定义阶段是一样的,但是@Configuration类中的@Bean是被动态代理了的

当处理完所有的Component类之后,就可以通过ConfigClass处理里面的@bean所生产的bean,所以还是在ConfigurationClassPostProcessor#processConfigBeanDefinitions方法内
最终走到的也是loadBeanDefinitionsForBeanMethod,然后调用了registerBeanDefinition

@Import注册
分为两步
processImports
第一步是将@Import内的类注册为ConfigClass,也是在ConfigurationClassParser#doProcessConfigurationClass 方法中,处理完ComponentScan就是@Import了
同理,也必须是在某个bean类上的Import才有作用

而processImport方法中,主要是有三部分,

ImportSelector
我们以事务为例,@EnableTransactionManagement注解,引入了TransactionManagementConfigurationSelector

在处理到有@EnableTransactionManagement的任意一个bean的时候,就会走到上面的第一种情况

selector字如其名,是通过某种选项来选择要构造的config类,
下面的是TransactionManagementConfigurationSelector的实现,由于他是继承的aop的selector,所以是由adviceMdoe决定的,两种返回的bean是不同的;比如默认是PROXY,则返回的是两个bean,{AutoProxyRegistrar,ProxyTransactionManagementConfiguration},之后会递归再次调用processImport方法

因此这种情况只是为了提供一种选择,最终落地的还是二三种情况
ImportBeanDefinitionRegistrar
事务的selector提供的AutoProxyRegistrar会在递归之后执行到第二种情况,最终添加到了BeanDefinitionRegister中去,实现了ImportBeanDefinitionRegistrar接口的类主要工作是实现registerBeanDefinitions方法,用于自定义beanDefinition,这个方法后面才会调到
ConfigurationClass
事务的selector提供的第二个bean就是一个普通bean,最终会走到这种情况

在这种情况下,会立即构建这个类为普通的config类
importStack.registerImport会在实例化之前设置一个元数据,除此之外不知道有啥用

执行registerBeanDefinitions
这个方法的入口是在之前@bean处理的方法后面,具体工作就是注册自定义的bean
比如MapperScan,就是注册指定包下所有的mapper和service
具体实现具体分析

内部注册
内部注册是指spring自己注册一些关键的bean,比如ConfigurationClassPostProcessor,通常是调用的AnnotationConfigUtils.registerAnnotationConfigProcessors方法注册的,一般是在refresh之前
