在上篇文章中,我们讨论了 refresh 的前四个方法,主要是对 ApplicationContext 上下文启动做一些准备工作。接下来对 invokeBeanFactoryPostProcessors 方法进行讨论,但该方法涉及 Spring 中一个非常重要的概念: BeanDefinition,所以,这里先对 BeanDefinition 进行讨论,这样也有利于完善 Spring 的知识体系。
首先看一下Spring一个大概的流程处理过程。
读取XML-> 解析XML封装成DOC对象 -> DOC对象转换成Spring beanDefinition对象 -> 获取beanDefinition对象开始创建bean

Spring容器启动的过程中,会将Bean定义信息解析成Spring内部的BeanDefinition结构。
Bean信息定义4种方式
1.API方式
2.XML文件方式
3.注解方式
类上标注@Compontent注解来定义一个bean
配置类中使用@Bean注解来定义bean
4.properties文件的方式
不管是是通过xml配置文件的标签,还是通过注解配置的@Bean,还是@Compontent标注的类,还是扫描得到的类,它最终都会被解析成一个BeanDefinition对象,最后我们的Bean工厂就会根据这份Bean的定义信息,对bean进行实例化、初始化等等操作。
BeanDefinition 是一个接口,它有多个实现类,这些实现类分别描述不同类型的 Bean,一个 BeanDefinition 描述了一个 Bean 实例,实例包含属性值、构造方法参数值以及更多实现信息。下面以XML文件配置方式从源码上跟一下BeanDefinition的注册过程。
1. 首先在ClassPathXmlApplicationContext设置了xml文件的位置,然后调用AbstractApplicationContext的refresh()方法。
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)throws BeansException {super(parent);//创建解析器,解析configLocationssetConfigLocations(configLocations);if (refresh) {// 核心方法refresh();}}
2.AbstractApplicationContext里obtainFreshBeanFactory()方法解析xml标签封装成BeanDefinition对象。
// AbstractApplicationContext.java/** 该方法是spring容器初始化的核心方法。是spring容器初始化的核心流程,是一个典型的父类模板设计模式的运用* 根据不同的上下文对象,会调到不同的上下文对象子类方法中** 核心上下文子类有:* ClassPathXmlApplicationContext* FileSystemXmlApplicationContext* AnnotationConfigApplicationContext* EmbeddedWebApplicationContext(springboot) 里面会用到钩子方法启动内嵌tomcat* */@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {//为容器初始化做准备prepareRefresh();/*非常重要1、创建BeanFactory对象* 2、xml解析* 传统标签解析:bean、import等* 自定义标签解析 如:<context:component-scan base-package="com.xiangxue.jack"/>* 自定义标签解析流程:* a、根据当前解析标签的头信息找到对应的namespaceUri* b、加载spring所以jar中的spring.handlers文件。并建立映射关系* c、根据namespaceUri从映射关系中找到对应的实现了NamespaceHandler接口的类* d、调用类的init方法,init方法是注册了各种自定义标签的解析类* e、根据namespaceUri找到对应的解析类,然后调用paser方法完成标签解析** 3、把解析出来的xml标签封装成BeanDefinition对象* */// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();......}}
3.AbstractApplicationContext里obtainFreshBeanFactory()调用refreshBeanFactory方法
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {refreshBeanFactory();......}
4.refreshBeanFactory方法调用loadBeanDefinitions方法
@Overrideprotected final void refreshBeanFactory() throws BeansException {......try {loadBeanDefinitions(beanFactory);}......}
5.在loadBeanDefinitions方法中创建XmlBeanDefinitionReader 对象用于解析xml文件
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {// Create a new XmlBeanDefinitionReader for the given BeanFactory.XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);// Configure the bean definition reader with this context's// resource loading environment.beanDefinitionReader.setEnvironment(this.getEnvironment());beanDefinitionReader.setResourceLoader(this);beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));// Allow a subclass to provide custom initialization of the reader,// then proceed with actually loading the bean definitions.initBeanDefinitionReader(beanDefinitionReader);loadBeanDefinitions(beanDefinitionReader);}
6.继续追踪loadBeanDefinitions方法,发现最后XmlBeanDefinitionReader 类中调用doLoadBeanDefinitions方法
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {......try {InputStream inputStream = encodedResource.getResource().getInputStream();try {InputSource inputSource = new InputSource(inputStream);if (encodedResource.getEncoding() != null) {inputSource.setEncoding(encodedResource.getEncoding());}return doLoadBeanDefinitions(inputSource, encodedResource.getResource());}......}......}
7.doLoadBeanDefinitions方法中把xml文件解析成document对象,然后注册BeanDefinitions
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {try {Document doc = doLoadDocument(inputSource, resource);return registerBeanDefinitions(doc, resource);}......}
8.继续调用registerBeanDefinitions方法,最终在DefaultBeanDefinitionDocumentReader类中调用doRegisterBeanDefinitions方法
@Overridepublic void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {this.readerContext = readerContext;Element root = doc.getDocumentElement();doRegisterBeanDefinitions(root);}
9.doRegisterBeanDefinitions中调用parseBeanDefinitions方法
protected void doRegisterBeanDefinitions(Element root) {......preProcessXml(root);parseBeanDefinitions(root, this.delegate);postProcessXml(root);this.delegate = parent;}
10.parseBeanDefinitions方法中调用parseDefaultElement方法
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {if (delegate.isDefaultNamespace(root)) {NodeList nl = root.getChildNodes();for (int i = 0; i < nl.getLength(); i++) {Node node = nl.item(i);if (node instanceof Element) {Element ele = (Element) node;if (delegate.isDefaultNamespace(ele)) {parseDefaultElement(ele, delegate);}else {delegate.parseCustomElement(ele);}}}}}
11.parseDefaultElement方法中调用processBeanDefinition方法
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {importBeanDefinitionResource(ele);}else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {processAliasRegistration(ele);}else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {processBeanDefinition(ele, delegate);}else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {// recursedoRegisterBeanDefinitions(ele);}}
12.processBeanDefinition方法中调用registerBeanDefinition
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);if (bdHolder != null) {bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);try {// Register the final decorated instance.BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());}......}
13.继续调用registerBeanDefinition方法,最终在DefaultLisableBeanfactory中把bean低昂易信息解析成BeanDefiantion对象并put到beanDefinitionMap中,把beanDefinition的名字add到beanDefinitionNames列表中
@Overridepublic void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {......if (hasBeanCreationStarted()) {// Cannot modify startup-time collection elements anymore (for stable iteration)synchronized (this.beanDefinitionMap) {this.beanDefinitionMap.put(beanName, beanDefinition);List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);updatedDefinitions.addAll(this.beanDefinitionNames);updatedDefinitions.add(beanName);this.beanDefinitionNames = updatedDefinitions;if (this.manualSingletonNames.contains(beanName)) {Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);updatedSingletons.remove(beanName);this.manualSingletonNames = updatedSingletons;}}}else {// Still in startup registration phasethis.beanDefinitionMap.put(beanName, beanDefinition);this.beanDefinitionNames.add(beanName);this.manualSingletonNames.remove(beanName);}this.frozenBeanDefinitionNames = null;}......}
14.执行完 registerBeanDefinition 方法后,Bean 的名称就被放入了beanDefinitionNames中,Bean 对应的 BeanDefinition被放入了beanDefinitionMap中,refresh方法中的后续方法会从这两个容器中获取beandefination信息来实例化bean对象。




