SpringIOC就是将对象的创建过程交给Spring容器,Spring容器在启动的时候会扫面所有的组件(带有@Component、@Bean等注解)存放在beanDefinationMap中,然后再需要创建对象的时候,取出bean定义信息,实例化对象即可。这里我们将分析一下组件扫描的过程。
注意:本文的中心思想是看Spring如何扫描到某个组件,并将其添加到容器中,其余问题不探究,不要走偏。
一、分析
从容器初始化入口出发
Spring初始化即容器的初始化,容器初始化的入口在AbstractApplicationContext.refresh()方法:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
//添加BeanPostProcessor到BeanFactory,用于在Bean初始化前后包装Bean
postProcessBeanFactory(beanFactory);
//调用BeanFactoryPostProcessor,所有的bean定义将在这里加载,这是我们这节关注的重
//点
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
initMessageSource();
initApplicationEventMulticaster();
onRefresh();
registerListeners();
finishBeanFactoryInitialization(beanFactory);
finishRefresh();
resetCommonCaches();
}
}
在invokeBeanFactoryPostProcessors的调用链中,其会从已有的容器中找到满足执行条件的所有BeanDefinitionRegistryPostProcessor类
调用其postProcessBeanDefinitionRegistry方法注册所有组件到容器中。这里你可以通过断掉调试,最终执行扫描所有类文件的BeanDefinitionRegistryPostProcessor类就是ConfigurationClassPostProcessor。、
那ConfigurationClassPostProcessor类是从哪里来的呢?其流程如下:
1.创建ApplicationContext的时候,优先会在构造函数中创建一个DefaultListableFactory容器。
public GenericApplicationContext() { this.beanFactory = new DefaultListableBeanFactory(); }
2.同时创建ApplicationContext的时候,创建AnnotatedBeanDefinitionReader对象(假设是Web环境)
public AnnotationConfigServletWebServerApplicationContext( DefaultListableBeanFactory beanFactory) { super(beanFactory); this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); }
3.创建AnnotatedBeanDefinitionReader对象时,注册ConfigurationClassPostProcess对象,对于解析各种组件注解。