Spring源码中最重要的一章之一,将分析Spring的核心:ApplicationContext。Bean的扫描、注册等基本上所有功能都是在这里实现的初始化。
一、待分析的源码
前面说的一直都是BeanFactory的东西,感觉BeanFactory已经把能做的都做了,那么ApplicationContext能做些什么呢?
简单一点说:ApplicationContext包含BeanFactory的所有功能,通常建议比BeanFactory优先。(个人感觉其实ApplicationContext就是一层壳,所有事情都委托给BeanFactory来做了,它只是做了初始化配置而已)
本文流程都围绕以下代码展开,代码和之前研究BeanFactory的时候基本一模一样,只是将XmlBeanFactory替换成了ClassPathXmlApplicationContext,他们又有什么区别呢?
1 | <?xml version="1.0" encoding="UTF-8"?> |
1 | public static void main(String[] args) { |
二、ApplicationContext的refresh方法
无论从ClassPathXmlApplicationContext类的哪个构造方法进入,最终都会进入AbstractApplicationContext类的refresh()方法,这个方法是研究ApplicationContext最重要的方法,务必记住它。
1 | public void refresh() throws BeansException, IllegalStateException { |
AbstractApplicationContext类中调用了一系列方法,看着十分清晰,这里对最重要的几个方法进行分析。
- obtainFreshBeanFactory方法
创建或获取BeanFactory。在Spring项目中,会创建一个DefaultListableBeanFactory,并对其中配置的xml文件进行读取和Bean注册;在SpringBoot项目中,会复用之前创建的DefaultListableBeanFactory,且不会对xml文件进行读取。
- invokeBeanFactoryPostProcessors方法
在Spring容器中找出实现了BeanFactoryPostProcessor接口的类并按一定的顺序执行。
在Spring项目中,obtainFreshBeanFactory方法在扫描到xml文件中的<context:component-scan>
标签时,调用AnnotationConfigUtils向BeanDefinitionMap中注册ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor等几个特别重要的类;而SpringBoot项目中,容器类型是AnnotationConfigServletWebServerApplicationContext,而这个类初始化了AnnotatedBeanDefinitionReader,这个类也调用了AnnotationConfigUtils往BeanDefinitionMap中注册了ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor等几个特别重要的类。
AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor分别实现对@Autowired、@Resource注解的支持,这个在之前已经说过了,他们会在Bean实例化后被调用。
而ConfigurationClassPostProcessor会在invokeBeanFactoryPostProcessors方法中首先执行,这个类会去找有@Configuration注解的Bean,然后使用ConfigurationClassParser去解析这个类,解析内容包含@PropertySources、@ComponentScans、@Import、@ImportResource、@Bean这几个注解。
值得注意的是,ConfigurationClassPostProcessor在Bean中解析到@ComponentScans注解时,会对该注解中标注的包进行扫描,扫描包中所有包含@Component的类,并将扫描到的类注册到BeanDefinitionMap中,@Controller、@Service、@Repository等几个注解也标注了@Component注解,所以也会被注册为Bean。ConfigurationClassPostProcessor也会将扫描出来@Bean注解的方法,放到BeanDefinitionMap中来实现了Bean的注册。@ImportResource同理,其中配置的xml文件也会在此被扫描。注意,这些Bean只是注册了,并还未实例化,实际实例化Bean是在后面的finishBeanFactoryInitialization方法中。
综上,invokeBeanFactoryPostProcessors通过调用ConfigurationClassPostProcessor完成了对@Component、@Controller、@Service、@Repository、@Bean等注解的扫描和Bean注册。而ConfigurationClassPostProcessor的注册是在ApplicationContext创建时进行的。
- registerBeanPostProcessors方法
从Spring容器中找出实现了BeanPostProcessor接口的Bean,然后设置到BeanFactory的beanPostProcessors变量中。
容器在创建时已经注册了一些实现BeanPostProcessor的Bean,但这些Bean只是BeanDefinition,还未实例化。registerBeanPostProcessors方法会实例化这些Bean,然后放到专门的beanPostProcessors变量中。
- onRefresh方法
一个模板方法,不同的容器会有不同的实现。
Spring的XmlWebApplicationContext容器未做什么我们关心的事。
SpringBoot的AnnotationConfigServletWebServerApplicationContext容器会在此处启动内置的Servlet容器,如Tomcat、Jetty。
- finishBeanFactoryInitialization方法
实例化所有预加载的Bean,刚才注册的BeanPostProcessor就会在实例化Bean的时候生效。
三、总结
ApplicationContext的关键方法是refresh()方法。
Spring项目中,obtainFreshBeanFactory方法完成了配置的xml文件的读取和Bean的注册。
基本上所有常见注解的扫描和Bean的注册,都是在invokeBeanFactoryPostProcessors方法中完成的。包括@Component、@Controller、@Service、@Repository、@Bean、@ImportResource注解解析出来的Bean,都会在此完成注册,但未实例化。
registerBeanPostProcessors方法会将创建容器时注册的BeanPostProcessor Bean,放到专门的beanPostProcessors变量中。AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor分别在实例化Bean时实现对@Autowired、@Resource注解的支持。
SpringBoot在onRefresh方法完成内置Servlet容器的启动。
大多数预加载的Bean都是在finishBeanFactoryInitialization方法中完成,通过调用BeanFactory的getBean方法实现。