Spring源码分析、资源抽象Resource、工厂BeanFactory、Bean定义读取器BeanDefinitionReader、Bean实例的注册流程解读

代码准备

新建一个简单的Java Bean

/**
 * @ClassName Student
 * @author: shouanzh
 * @Description POJO: Plain Old Java Object 简单的java对象,也就是普通JavaBeans
 * @date 2022/1/3 18:19
 */
public class Student {

    private String name;

    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

resources目录下编写applicationContext.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="student" class="com.kernel.spring.bean.Student">
        <property name="age" value="26"/>
        <property name="name" value="zhangsan"/>
    </bean>

</beans>

一个main方法

/*
    IOC(Inverse of Control,控制反转)  本该由使用者来创建对象我们将指定资源交给工厂 此时由工厂进行创建其对应对象 将其加载到内存当中
    DI (Dependency Injection,依赖注入) A中依赖B此时将A加载到IOC 此时B也得被加载到IOC 此时A才能被调用。 此时就称为依赖注入

    关于Spring容器管理Bean的过程以及加载模式:

    1.需要将bean的定义信息声明在Spring的配置文件当中
    2.需要通过Spring抽象出的各种Resource来指定对应的配置文件。
    3.需要显示的声明一个Spring工厂,该工厂用来掌控我们在配置文件中所声明的各种bean以及bean之间的依赖关系与注入关系
    4.需要定义一个配置信息读取器,该读取器用来读取之前所定义的bean配置文件信息
    5.读取器的作用是读取我们所声明的配置文件信息,并且将读取后的信息装配到之前所声明的工厂当中
    6.需要将读取器与工厂以及资源对象进行相应的关联处理。
    7.工厂所管理的全部对象装配完毕,可以供客户端直接调用,获取客户端想要使用的各种bean对象。

    Spring对于Bean管理的核心组件:

    1.资源抽象ClassPathResource
    2.工厂DefaultListableBeanFactory
    3.配置信息读取器XmlBeanDefinitionReader (当读取器将资源读取到工厂当中 此时我们只需要跟工厂打交道)

    BeanFactory 是Spring工厂 最顶层的抽象(类似Object类) 我们使用的抽象bean工厂都是直接或间接的衍生至BeanFactory

    关于Spring Bean实例的注册流程

    1.定义好Spring的配置文件。
    2.通过Resource对象奖Spring配置文件进行抽象,抽象成一个具体的Resource对象(如ClassPathResource)。
    3.定义好将要使用的Bean工厂(各种BeanFactory)。
    4.定义好XmlBeanDefinitionReader对象,并将工厂对象作为参数传递进去,从而构建好二者之间的关联关系。
    5.通过XmlBeanDefinitionReader对象读取之前所抽取出的Resource对象。
    6.流程开始进行解析。
    7.针对XML文件进行各种元素以及元素属性的解析,这里面,真正的解析是通过BeanDefinitionParserDelegate对象来完成的(委托模式)
    8.通过BeanDefinitionParserDelegate对象在解析XML文件时,又使用到了模版方法设计模式(pre,process,post)。
    9.当所有的bean标签元素都解析完毕后,开始定义一个BeanDefinition对象,该对象是一个非常重要的对象,里面容纳了一个Bean相关的所有属性。
    10.BeanDefinition对象创建完毕后,Spring又会创建一个BeanDefinitionHolder对象来持有这个BeanDefinition对象。
    11.BeanDefinitionHolder对象主要包含俩部分内容:beanName与BeanDefinition。
    12.工厂会将解析出来的Bean信息存放到内部的一个ConcurrentHashMap中,该Map的键是beanName(唯一),值是BeanDefinition对象。
    13.调用Bean解析完毕的触发动作,从而触发相应的监听器的方法的执行(使用了观察者模式)。

 */
public class SpringClient {
    public static void main(String[] args) {
        // 类路径下的资源 将其具体抽象成资源对象
        Resource resource = new ClassPathResource("applicationContext.xml");
        // 创建Bean工厂实例
        DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
        // 创建bean读取器实例
        BeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
        // 将读取的资源放到defaultListableBeanFactory工厂当中
        beanDefinitionReader.loadBeanDefinitions(resource);
        // 读取完我们需要哪个对象找工厂要
        Student student = (Student) defaultListableBeanFactory.getBean("student");
        Student student2 = (Student) defaultListableBeanFactory.getBean("student");

        System.out.println(student.getAge());
        System.out.println(student.getName());
        System.out.println(student == student2);

    }
}

Spring容器管理Bean的过程以及加载模式

  1. 需要将bean的定义信息声明在Spring的配置文件当中
  2. 需要通过Spring抽象出的各种Resource来指定对应的配置文件。
  3. 需要显示的声明一个Spring工厂,该工厂用来掌控我们在配置文件中所声明的各种bean以及bean之间的依赖关系与注入关系
  4. 需要定义一个配置信息读取器,该读取器用来读取之前所定义的bean配置文件信息
  5. 读取器的作用是读取我们所声明的配置文件信息,并且将读取后的信息装配到之前所声明的工厂当中
  6. 需要将读取器与工厂以及资源对象进行相应的关联处理。
  7. 工厂所管理的全部对象装配完毕,可以供客户端直接调用,获取客户端想要使用的各种bean对象。

Spring对于Bean管理的核心组件

  1. 资源抽象ClassPathResource
  2. 工厂DefaultListableBeanFactory
  3. 配置信息读取器XmlBeanDefinitionReader (当读取器将资源读取到工厂当中 此时我们只需要跟工厂打交道)

IOC和DI概念

  • IOC(Inverse of Control,控制反转) 本该由使用者来创建对象我们将指定资源交给工厂 此时由工厂进行创建其对应对象 将其加载到内存当中
  • DI (Dependency Injection,依赖注入) A中依赖B此时将A加载到IOC 此时B也得被加载到IOC 此时A才能被调用。 此时就称为依赖注入

1.Resource概述及ClassPathResource源码分析

从底层资源的实际类型(例如文件或类路径资源)中抽象出来的资源描述符的接口。
Resource实现有:文件系统资源(FileSystemResource)、类路径资源(ClassPathResource)、字节数组资源(ByteArrayResource)、URL资源(UrlResource)等。

Resource源码

public interface Resource extends InputStreamSource {
	/**
     * 资源是否存在
     */
	boolean exists();

	/**
     * 资源是否可读
     */
	default boolean isReadable() {
		return exists();
	}

	default boolean isOpen() {
		return false;
	}

	/**
     * 资源是否为 File
     */
	default boolean isFile() {
		return false;
	}

	URL getURL() throws IOException;

	URI getURI() throws IOException;

	File getFile() throws IOException;

	default ReadableByteChannel readableChannel() throws IOException {
		return Channels.newChannel(getInputStream());
	}

	long contentLength() throws IOException;

	long lastModified() throws IOException;

	Resource createRelative(String relativePath) throws IOException;

	/**
     * 资源名
     */
	@Nullable
	String getFilename();

	String getDescription();
}

ClassPathResource源码分析

类路径下的资源 将其具体抽象成资源对象

补充:
@NonNull 可以标注在方法、字段、参数之上,表示对应的值不可以为空
@Nullable 注解可以标注在方法、字段、参数之上,表示对应的值可以为空

// 类路径下的资源 将其具体抽象成资源对象
Resource resource = new ClassPathResource("applicationContext.xml");
/**
  * 类路径资源的Resource实现。 使用给定的ClassLoader或给定的Class来加载资源。
  */
public class ClassPathResource extends AbstractFileResolvingResource {

	// 文件路径 如:applicationContext.xml
	private final String path;

	// 类加载器
	@Nullable
	private ClassLoader classLoader;

	@Nullable
	private Class<?> clazz;

	// 构造函数
	// 为ClassLoader使用创建一个新的ClassPathResource 。
	// 前导斜杠将被删除,因为 ClassLoader 资源访问方法将不接受它。
    // 线程上下文类加载器将用于加载资源。
	public ClassPathResource(String path) {
		this(path, (ClassLoader) null);
	}
	
	// 为ClassLoader使用创建一个新的ClassPathResource 。 
	// 前导斜杠将被删除,因为 ClassLoader 资源访问方法将不接受它
	public ClassPathResource(String path, @Nullable ClassLoader classLoader) {
		Assert.notNull(path, "Path must not be null");
		// 将传过来的路径进行校正得到合法的路径
		String pathToUse = StringUtils.cleanPath(path);
		if (pathToUse.startsWith("/")) {
			pathToUse = pathToUse.substring(1);
		}
		// 初始化文件路径
		this.path = pathToUse;
		// 指定类加载器,如果没有传类加载器,则用默认的类加载器,翻看源码是:Thread.currentThread().getContextClassLoader()
		this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
	}

	public ClassPathResource(String path, @Nullable Class<?> clazz) {
		Assert.notNull(path, "Path must not be null");
		this.path = StringUtils.cleanPath(path);
		this.clazz = clazz;
	}

	@Deprecated
	protected ClassPathResource(String path, @Nullable ClassLoader classLoader, @Nullable Class<?> clazz) {
		this.path = StringUtils.cleanPath(path);
		this.classLoader = classLoader;
		this.clazz = clazz;
	}

	// 获取配置文件路径
	public final String getPath() {
		return this.path;
	}

	// 获取类加载器
	@Nullable
	public final ClassLoader getClassLoader() {
		return (this.clazz != null ? this.clazz.getClassLoader() : this.classLoader);
	}

	// 判断文件是否存在
	@Override
	public boolean exists() {
		return (resolveURL() != null);
	}

	@Nullable
	protected URL resolveURL() {
		try {
			if (this.clazz != null) {
				return this.clazz.getResource(this.path);
			}
			else if (this.classLoader != null) {
				return this.classLoader.getResource(this.path);
			}
			else {
				return ClassLoader.getSystemResource(this.path);
			}
		}
		catch (IllegalArgumentException ex) {
			// Should not happen according to the JDK's contract:
			// see https://github.com/openjdk/jdk/pull/2662
			return null;
		}
	}

	// 此方法继承自InputStreamSource,ClassPathResource实现了具体逻辑
    // 主要就是通过类加载器加载配置文件到内存 InputStream中
	@Override
	public InputStream getInputStream() throws IOException {
		InputStream is;
		if (this.clazz != null) {
			is = this.clazz.getResourceAsStream(this.path);
		}
		else if (this.classLoader != null) {
			is = this.classLoader.getResourceAsStream(this.path);
		}
		else {
			is = ClassLoader.getSystemResourceAsStream(this.path);
		}
		if (is == null) {
			throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
		}
		return is;
	}

	@Override
	public URL getURL() throws IOException {
		URL url = resolveURL();
		if (url == null) {
			throw new FileNotFoundException(getDescription() + " cannot be resolved to URL because it does not exist");
		}
		return url;
	}

	@Override
	public Resource createRelative(String relativePath) {
		String pathToUse = StringUtils.applyRelativePath(this.path, relativePath);
		return (this.clazz != null ? new ClassPathResource(pathToUse, this.clazz) :
				new ClassPathResource(pathToUse, this.classLoader));
	}

	@Override
	@Nullable
	public String getFilename() {
		return StringUtils.getFilename(this.path);
	}

	@Override
	public String getDescription() {
		StringBuilder builder = new StringBuilder("class path resource [");
		String pathToUse = this.path;
		if (this.clazz != null && !pathToUse.startsWith("/")) {
			builder.append(ClassUtils.classPackageAsResourcePath(this.clazz));
			builder.append('/');
		}
		if (pathToUse.startsWith("/")) {
			pathToUse = pathToUse.substring(1);
		}
		builder.append(pathToUse);
		builder.append(']');
		return builder.toString();
	}

	@Override
	public boolean equals(@Nullable Object other) {
		if (this == other) {
			return true;
		}
		if (!(other instanceof ClassPathResource)) {
			return false;
		}
		ClassPathResource otherRes = (ClassPathResource) other;
		return (this.path.equals(otherRes.path) &&
				ObjectUtils.nullSafeEquals(this.classLoader, otherRes.classLoader) &&
				ObjectUtils.nullSafeEquals(this.clazz, otherRes.clazz));
	}

	@Override
	public int hashCode() {
		return this.path.hashCode();
	}

}

ClassPathResource 初始化时主要保存 ClassPath路径下配置文件的路径,选择类加载器,然后在继承自 InputStreamResource 的方法 getInputStream中 通过 类加载器加载配置文件到内存(InputStream)中,供Reader使用。

2.创建Bean工厂实例

// 创建Bean工厂实例
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();

看一下DefaultListableBeanFactory的类图。
在这里插入图片描述
首先跟进DefaultListableBeanFactory类的无参构造函数

/**
 * Create a new DefaultListableBeanFactory.
 */
public DefaultListableBeanFactory() {
	super();
}

可以看到什么都没有做,只是调用了父类的无参构造函数。我们来看看它的父类AbstractAutowireCapableBeanFactory的无参构造函数

/**
 * Create a new AbstractAutowireCapableBeanFactory.
 */
public AbstractAutowireCapableBeanFactory() {
	super();
	ignoreDependencyInterface(BeanNameAware.class);
	ignoreDependencyInterface(BeanFactoryAware.class);
	ignoreDependencyInterface(BeanClassLoaderAware.class);
	if (NativeDetector.inNativeImage()) {
		this.instantiationStrategy = new SimpleInstantiationStrategy();
	}
	else {
		this.instantiationStrategy = new CglibSubclassingInstantiationStrategy();
	}
}

可以看到其调用了父类的无参构造函数,接着调用了三次ignoreDependencyInterface方法,该方法其作用是指定自动装配(autowiring)的时候忽略的接口

打开BeanFactory ignoreDependencyInterface方法的正确姿势:参考https://www.jianshu.com/p/3c7e0608ff1f

我们来看看其调用的父类AbstractBeanFactory的无参构造函数

/**
 * Create a new AbstractBeanFactory.
 */
public AbstractBeanFactory() {
}

其中什么都没有做。到这里没有再显式地调用父类的构造函数。
当我们再看AbstractBeanFactory的父类FactoryBeanRegistrySupport,FactoryBeanRegistrySupport的父类DefaultSingletonBeanRegistry,DefaultSingletonBeanRegistry的父类SimpleAliasRegistry的源码会发现其都没有写构造方法,也就是说其都是默认的空的无参构造函数。

3.Spring配置信息读取器加载流程解析

// 创建bean读取器实例
BeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);

XmlBeanDefinitionReader,xml的bean定义的读取器

这里新建一个XmlBeanDefinitionReader对象,并以此前创建的DefaultListableBeanFactory的对象defaultListableBeanFactory作为参数。

/**
  *为给定的bean工厂创建新的XmlBeanDefinitionReader。
  *参数:
  *registry–以BeanDefinitionRegistr的形式将bean定义加载到其中的BeanFactory
  */
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
	super(registry);
}

再看其构造器,发现需要的参数只需要实现BeanDefinitionRegistry 接口即可,观察类图或者查看源码可知DefaultListableBeanFactory实现了BeanDefinitionRegistry接口

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
		implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {

在这里插入图片描述

看一下BeanDefinitionRegistry源码
该接口中有bean定义数量和bean定义名称两个属性,有注册bean定义、移除bean定义,得到bean定义、判断是否包含bean定义、bean名称是否在使用等方法。

public interface BeanDefinitionRegistry extends AliasRegistry {

	/**
	 * 在此注册表中注册一个新的bean定义。
	 */
	void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException;

	/**
	 * 删除给定名称的Bean定义。
	 */
	void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

	/**
	 * 返回给定bean名称的bean定义。
	 */
	BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

	/**
	 * 检查此注册表是否包含具有给定名称的bean定义。
	 */
	boolean containsBeanDefinition(String beanName);

	/**
	 * 返回此注册表中定义的所有bean的名称。
	 */
	String[] getBeanDefinitionNames();

	/**
	 * 返回注册表中定义的bean数。
	 */
	int getBeanDefinitionCount();

	/**
	 * 确定给定的bean名称是否已在此注册表中使用
	 */
	boolean isBeanNameInUse(String beanName);

}

XmlBeanDefinitionReader调用了父类的构造器如下:

/*
为给定的bean工厂创建一个新的AbstractBeanDefinitionReader。
如果传入的bean工厂不仅实现BeanDefinitionRegistry接口,还实现ResourceLoader接口,那么它也将用作默认的ResourceLoader。
如果给定普通BeanDefinitionRegistry,默认的ResourceLoader将是PathMatchingResourcePatternResolver。
如果传入的bean工厂也实现了Environmentable,那么该读取器将使用它的环境。
否则,读取器将初始化并使用StandardEnvironment。
所有ApplicationContext实现都支持环境,而普通BeanFactory实现则不支持环境。
参数:
registry–以BeanDefinitionRegistry的形式加载bean定义的BeanFactory
*/
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
	// bean工厂 defaultListableBeanFactory
	this.registry = registry;

	// Determine ResourceLoader to use.
	// ResourceLoader 资源加载器
	if (this.registry instanceof ResourceLoader) {
		this.resourceLoader = (ResourceLoader) this.registry;
	}
	else {
		this.resourceLoader = new PathMatchingResourcePatternResolver();
	}

	// Inherit Environment if possible
	//初始化environment
	if (this.registry instanceof EnvironmentCapable) {
		this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
	}
	else {
		this.environment = new StandardEnvironment();
	}
}

首先进行必要的判空和赋值,然后判断传入的参数(这个registry对象参数肯定实现了BeanDefinitionRegistry ,但是否实现了ResourceLoader未知)是否实现了ResourceLoader。

我们这里传入的DefaultListableBeanFactory对象没有实现这个接口,因此在else里面,会新建一个PathMatchingResourcePatternResolver对象。

ResourceLoader提供 ClassPath下单资源文件的载入,而ResourcePatternResolver提供了多资源文件的载入。ResourcePatternResolver有一个实现类:PathMatchingResourcePatternResolver

初始化environment
Environment 是用来获取配置文件中的属性值。它主要为我们的应用程序环境的两个方面的支持:profiles 和 properties。

在这里插入图片描述
多种配置信息来源的一种抽象和提取。Environment定义了Profiles的方法处理。PropertyResolver定义了Property属性相关的处理

4.将读取的资源放到defaultListableBeanFactory工厂当中

// 将读取的资源放到defaultListableBeanFactory工厂当中
beanDefinitionReader.loadBeanDefinitions(resource);

这里使用了XmlBeanDefinitionReader类的loadBeanDefinitions方法加载Resource类的对象resource

/*
从指定的XML文件加载bean定义。
参数:
resource–XML文件的资源描述符
返回:
找到的bean定义数
抛出:
BeanDefinitionStoreException–在加载或分析错误的情况下
*/
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
	// EncodedResource里封装的待解析的资源 和 编码的信息
	return loadBeanDefinitions(new EncodedResource(resource));
}

这里首先将resource进行encode,作用是进行编码。然后我们看看loadBeanDefinitions的具体实现。

/*
从指定的XML文件加载bean定义。
参数:
encodedResource–XML文件的资源描述符,允许指定用于解析文件的编码
返回:
找到的bean定义数
抛出:
BeanDefinitionStoreException–在加载或分析错误的情况下
*/
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
	Assert.notNull(encodedResource, "EncodedResource must not be null");
	if (logger.isTraceEnabled()) {
		logger.trace("Loading XML bean definitions from " + encodedResource);
	}

	// XmlBeanDefinitionReader内部维护了一个private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded变量,
	// 用于保存最近被加载的资源。
	Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();

	// 然后将传入的参数加入currentResources中
	// set集合add 返回false 说明该资源已经加载
	// 防止资源导入中AB互相依赖 循环导入 陷入死循环
	if (!currentResources.add(encodedResource)) {
		throw new BeanDefinitionStoreException(
				// 检测到“+encodedResource+”的循环加载-检查您的导入定义!
				"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
	}
	
	// 获取资源文件的输入流 JDK 1.7 新特性 try-with-resources 自动释放资源
	try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
		// SAX以流的方式解析XML文件 文件较大时效率比dom方式快
		InputSource inputSource = new InputSource(inputStream);
		// 如果编码不为空
		if (encodedResource.getEncoding() != null) {
			// 采用encodedResource的编码格式 解析xml
			inputSource.setEncoding(encodedResource.getEncoding());
		}
		return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
	}
	catch (IOException ex) {
		throw new BeanDefinitionStoreException(
				"IOException parsing XML document from " + encodedResource.getResource(), ex);
	}
	finally {
		// 最后将传入的资源从最近被加载的资源中删除。
		currentResources.remove(encodedResource);
		if (currentResources.isEmpty()) {
			// threadLocal 是弱引用 使用完需要主动关闭 防止内存泄露
			this.resourcesCurrentlyBeingLoaded.remove();
		}
	}
}

接下来看一下doLoadBeanDefinitions方法的实现

/*
实际上,从指定的XML文件加载bean定义。
参数:
inputSource–要读取的SAX inputSource
resource–XML文件的资源描述符
返回:
找到的bean定义数
抛出:
BeanDefinitionStoreException–在加载或分析错误的情况下
*/
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {

	try {
		/*
		Document接口表示整个HTML或XML文档。
		从概念上讲,它是文档树的根,提供对文档数据的主要访问。
		将XML数据封装成一个Document 他表示整个HTML或XML文档
		*/
		Document doc = doLoadDocument(inputSource, resource);
		// 解析Document 文档数据 返回解析bean数量
		int count = registerBeanDefinitions(doc, resource);
		if (logger.isDebugEnabled()) {
			logger.debug("Loaded " + count + " bean definitions from " + resource);
		}
		return count;
	}
	catch (BeanDefinitionStoreException ex) {
		throw ex;
	}
	catch (SAXParseException ex) {
		throw new XmlBeanDefinitionStoreException(resource.getDescription(),
				"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
	}
	catch (SAXException ex) {
		throw new XmlBeanDefinitionStoreException(resource.getDescription(),
				"XML document from " + resource + " is invalid", ex);
	}
	catch (ParserConfigurationException ex) {
		throw new BeanDefinitionStoreException(resource.getDescription(),
				"Parser configuration exception parsing XML from " + resource, ex);
	}
	catch (IOException ex) {
		throw new BeanDefinitionStoreException(resource.getDescription(),
				"IOException parsing XML document from " + resource, ex);
	}
	catch (Throwable ex) {
		throw new BeanDefinitionStoreException(resource.getDescription(),
				"Unexpected exception parsing XML document from " + resource, ex);
	}
}

然后使用this.documentLoader.loadDocument方法来加载xml文档

private DocumentLoader documentLoader = new DefaultDocumentLoader();
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
	return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
			getValidationModeForResource(resource), isNamespaceAware());
}

让我们来看看DefaultDocumentLoader类的loadDocument方法。

@Override
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
		ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {

	DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
	if (logger.isTraceEnabled()) {
		logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");
	}
	DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
	return builder.parse(inputSource);
}

它有几个参数,分别是输入源inputSource,实体解析器entityResolver,错误处理器errorHandler,XML验证模式validationMode,namespaceAware。最终落实到DocumentBuilder的parse方法。

接着调用registerBeanDefinitions(doc, resource);

/*
注册给定DOM文档中包含的bean定义。由loadBeanDefinitions调用。
创建解析器类的新实例,并对其调用registerBeanDefinitions。
参数:
doc–DOM文档
resource–资源描述符(用于上下文信息)
返回:
找到的bean定义数
*/
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
	// 创建BeanDefinitionDocumentReader资源读取器,用于从XML文档中实际读取bean定义。
	BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
	// 获取工厂解析之前解析的数量
	int countBefore = getRegistry().getBeanDefinitionCount();
	// 通过解析器正式开始解析
	documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
	// 解析后解析数-解析前解析数
	return getRegistry().getBeanDefinitionCount() - countBefore;
}

中场休息-小小结
在这里插入图片描述
紧接着DefaultBeanDefinitionDocumentReader调用其registerBeanDefinitions方法

documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
	this.readerContext = readerContext;
	doRegisterBeanDefinitions(doc.getDocumentElement());
}


@SuppressWarnings("deprecation") 
// 其中root代表了xml文档的根元素 <beans></beans>
// 在给定的根<beans/>元素中注册每个bean定义。
protected void doRegisterBeanDefinitions(Element root) {
	
	BeanDefinitionParserDelegate parent = this.delegate;
	// 采用委托模式解析<beans>
	this.delegate = createDelegate(getReaderContext(), root, parent);

    // delegate是默认的命名空间"http://www.springframework.org/schema/beans";
	if (this.delegate.isDefaultNamespace(root)) {
		// PROFILE_ATTRIBUTE = "profile";
		String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
		// 判断是否有内容
		if (StringUtils.hasText(profileSpec)) {
			String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
					profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
		
			if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
				if (logger.isDebugEnabled()) {
					logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
							"] not matching: " + getReaderContext().getResource());
				}
				return;
			}
		}
	}

	/*该地方用到了模板方法模式
	父类规定好执行流程 具体执行逻辑由子类自由扩展 并严格遵守父类定义好的执行流程
	*/
	preProcessXml(root); // 文档解析之前可以做的事情 可扩展 
	// 使用委托对象去解析rootElement数据
	parseBeanDefinitions(root, this.delegate);
	postProcessXml(root); //文档解析之后可以做的事情

	//委托对象重新赋值
	this.delegate = parent;
}

我们来看看parseBeanDefinitions方法

// Parse the elements at the root level in the document: "import", "alias", "bean".
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);
				}
			}
		}
	}
	else {
		delegate.parseCustomElement(root);
	}
}

首先判断是否是默认的命名空间,如果是,则执行parseDefaultElement,否则执行parseCustomElement。

我们这里是使用的默认的命名空间,因此接着调用getChildNodes方法获得<beans></beans>下面的子节点,也就是<bean></bean>。

然后对于每个子节点,根据当前是否是默认命名空间来调用不同方法解析。

我们这里先只看parseDefaultElement。

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)) {
		// recurse
		doRegisterBeanDefinitions(ele);
	}
}

这里分了3种情况,分别是节点标签名对应import alias 和bean的情况。
它们分别处理<import/> <alias/>和<bean/>
我们这里只涉及bean的解析。来看看。
在这里插入图片描述

/**
 *  完成两件事情
 * 1.处理给定的bean元素,解析bean定义
 * 2.并将其注册到工厂中。
 */
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
	 // BeanDefinitionHolder顾名思义就是对BeanDefinition的持有,
	 // 同时持有的包括BeanDefinition的名称和别名
	 // 一个BeanDefinition 对应一个bean标签 
	BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
	if (bdHolder != null) {
		bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
		try {
			// 这里是向IoC容器注册解析得到的BeanDefinition的地方。
			BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
		}
		catch (BeanDefinitionStoreException ex) {
			getReaderContext().error("Failed to register bean definition with name '" +
					bdHolder.getBeanName() + "'", ele, ex);
		}
		// 发送注册事件
		getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
	}
}

parseBeanDefinitionElement

@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
	// 获取id 和 name属性值
	String id = ele.getAttribute(ID_ATTRIBUTE);
	String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
	// 获取别名
	List<String> aliases = new ArrayList<>();
	if (StringUtils.hasLength(nameAttr)) {
		String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
		aliases.addAll(Arrays.asList(nameArr));
	}

	// beanName = id值
	String beanName = id;
	if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
		beanName = aliases.remove(0);
		if (logger.isTraceEnabled()) {
			logger.trace("No XML 'id' specified - using '" + beanName +
					"' as bean name and " + aliases + " as aliases");
		}
	}

	if (containingBean == null) {
		checkNameUniqueness(beanName, aliases, ele);
	}
	// 获取beanDefinition 对象 里面封装了当前bean的所有信息
	AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
	if (beanDefinition != null) {
		if (!StringUtils.hasText(beanName)) {
			try {
				if (containingBean != null) {
					beanName = BeanDefinitionReaderUtils.generateBeanName(
							beanDefinition, this.readerContext.getRegistry(), true);
				}
				else {
					beanName = this.readerContext.generateBeanName(beanDefinition);
					// Register an alias for the plain bean class name, if still possible,
					// if the generator returned the class name plus a suffix.
					// This is expected for Spring 1.2/2.0 backwards compatibility.
					// 获取到bean类的名字
					String beanClassName = beanDefinition.getBeanClassName();
					if (beanClassName != null &&
							beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
							!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
						aliases.add(beanClassName);
					}
				}
				if (logger.isTraceEnabled()) {
					logger.trace("Neither XML 'id' nor 'name' specified - " +
							"using generated bean name [" + beanName + "]");
				}
			}
			catch (Exception ex) {
				error(ex.getMessage(), ele);
				return null;
			}
		}
		String[] aliasesArray = StringUtils.toStringArray(aliases);
		// beanDefinition 解析的<Bean>标签下所有标签数据,id对应的name 别名数组
		return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
	}

	return null;
}

在这里插入图片描述
BeanDefinitionHolder是BeanDefinition的封装
而BeanDefinition可以看成是<bean>定义的抽象。
具体的加载过程由BeanDefinitionParserDelegate对XML元素的信息按照Spring的Bean规则进行解析得到的,入口是parseBeanDefinitionElement

// 解析bean定义本身,不考虑名称或别名。如果在分析bean定义期间出现问题,则可能返回null。
@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(
		Element ele, String beanName, @Nullable BeanDefinition containingBean) {

	this.parseState.push(new BeanEntry(beanName));

	String className = null;
	// CLASS_ATTRIBUTE = "class";
	// 我们这里 <bean id="student" class="com.kernel.spring.bean.Student">
	if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
		className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
	}
	String parent = null;
	//如果元素有parent属性
	if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
	    //得到parent节点
		parent = ele.getAttribute(PARENT_ATTRIBUTE);
	}

	try {
		// 根据parent创建AbstractBeanDefinition
		AbstractBeanDefinition bd = createBeanDefinition(className, parent);
		// 解析bean定义的属性
		parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
		// 为bean定义设置描述
		bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

		// 解析元数据
		parseMetaElements(ele, bd);
		parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
		parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

		// 解析构造器参数元素
		parseConstructorArgElements(ele, bd);
		// 解析property属性元素 如 <property name="age" value="26"/>
		parsePropertyElements(ele, bd);
		parseQualifierElements(ele, bd);

		bd.setResource(this.readerContext.getResource());
		bd.setSource(extractSource(ele));

		// BeanDefinition 装配完毕
		return bd;
	}
	catch (ClassNotFoundException ex) {
		error("Bean class [" + className + "] not found", ele, ex);
	}
	catch (NoClassDefFoundError err) {
		error("Class that bean class [" + className + "] depends on not found", ele, err);
	}
	catch (Throwable ex) {
		error("Unexpected failure during bean definition parsing", ele, ex);
	}
	finally {
		this.parseState.pop();
	}

	return null;
}

其中createBeanDefinition创建一个BeanDefinition的实现GenericBeanDefinition。然后调用parseConstructorArgElements、parsePropertyElements等解析构造器参数,解析属性元素等。

createBeanDefinition中直接使用BeanDefinitionReaderUtils.createBeanDefinition创建bean。

/*
为给定的类名和父名称创建bean定义。
参数:
className–bean类的名称
parentName–bean的父bean的名称
返回:
新创建的bean定义
*/
protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
			throws ClassNotFoundException {

	return BeanDefinitionReaderUtils.createBeanDefinition(
			parentName, className, this.readerContext.getBeanClassLoader());
}
public static AbstractBeanDefinition createBeanDefinition(
			@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {

	GenericBeanDefinition bd = new GenericBeanDefinition();
	bd.setParentName(parentName);
	if (className != null) {
		if (classLoader != null) {
			bd.setBeanClass(ClassUtils.forName(className, classLoader));
		}
		else {
			bd.setBeanClassName(className);
		}
	}
	return bd;
}

AbstractBeanDefinition

// beanClass代表俩层含义
// 1. Class对象
// 2. 待实例化的那个bean字符串表示 className
@Nullable
private volatile Object beanClass;

@Override
public void setBeanClassName(@Nullable String beanClassName) {
	this.beanClass = beanClassName;
}

public String getBeanClassName() {
	Object beanClassObject = this.beanClass;
	if (beanClassObject instanceof Class) {
		return ((Class<?>) beanClassObject).getName();
	}
	else {
		return (String) beanClassObject;
	}
}

public void setBeanClass(@Nullable Class<?> beanClass) {
	this.beanClass = beanClass;
}

其中使用了ClassUtils加载类的定义,然后为BeanDefinition设置了bean的class属性。

parseBeanDefinitionAttributes 解析Bean定义属性
bean里各种属性
在这里插入图片描述

public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
		@Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {

	// 处理作用域
	if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
		error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
	}
	else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
		// 设置作用域
		bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
	}
	else if (containingBean != null) {
		// Take default from containing bean in case of an inner bean definition.
		bd.setScope(containingBean.getScope());
	}

	if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
		bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
	}

	String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
	if (isDefaultValue(lazyInit)) {
		lazyInit = this.defaults.getLazyInit();
	}
	bd.setLazyInit(TRUE_VALUE.equals(lazyInit));

	String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
	bd.setAutowireMode(getAutowireMode(autowire));

	if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
		String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
		bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
	}

	String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
	if (isDefaultValue(autowireCandidate)) {
		String candidatePattern = this.defaults.getAutowireCandidates();
		if (candidatePattern != null) {
			String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
			bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
		}
	}
	else {
		bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
	}

	if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
		bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
	}

	if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
		String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
		bd.setInitMethodName(initMethodName);
	}
	else if (this.defaults.getInitMethod() != null) {
		bd.setInitMethodName(this.defaults.getInitMethod());
		bd.setEnforceInitMethod(false);
	}

	if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
		String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
		bd.setDestroyMethodName(destroyMethodName);
	}
	else if (this.defaults.getDestroyMethod() != null) {
		bd.setDestroyMethodName(this.defaults.getDestroyMethod());
		bd.setEnforceDestroyMethod(false);
	}

	if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
		bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
	}
	if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
		bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
	}

	return bd;
}

spring的scope属性默认是单例
在这里插入图片描述
然后回到:DefaultBeanDefinitionDocumentReader

/**
 *  完成两件事情
 * 1.处理给定的bean元素,解析bean定义
 * 2.并将其注册到工厂中。
 */
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
	 // BeanDefinitionHolder顾名思义就是对BeanDefinition的持有,
	 // 同时持有的包括BeanDefinition的名称和别名
	 // 一个BeanDefinition 对应一个bean标签 
	BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
	if (bdHolder != null) {
		// 对BeanDefinitionHolder进一步封装 如自定义标签
		bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
		try {
			// 这里是向IoC容器注册解析得到的BeanDefinition的地方。
			BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
		}
		catch (BeanDefinitionStoreException ex) {
			getReaderContext().error("Failed to register bean definition with name '" +
					bdHolder.getBeanName() + "'", ele, ex);
		}
		// 发送注册事件
		getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
	}
}

解析bean定义后,使用如下方法注册bean定义,这里的getReaderContext().getRegistry()就是最开始新建的工厂对象DefaultListableBeanFactory。

// Register the final decorated instance.
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
/*
向给定的bean工厂注册给定的bean定义。
参数:
definitionHolder–bean定义,包括名称和别名
注册表–要注册的bean工厂
抛出:
BeanDefinitionStoreException–如果注册失败
*/
public static void registerBeanDefinition(
		BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
		throws BeanDefinitionStoreException {

	// Register bean definition under primary name.
	// 获取bean的名字
	String beanName = definitionHolder.getBeanName();
	// 将对应的bean注册到工厂上 
	registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

	// Register aliases for bean name, if any.
	String[] aliases = definitionHolder.getAliases();
	// 注册bean名称的别名
	if (aliases != null) {
		for (String alias : aliases) {
			registry.registerAlias(beanName, alias);
		}
	}
}

在这里插入图片描述
再向给定的bean工厂注册给定的bean定义前已经获取到了bean的所有信息。

registry.registerBeanDefinition将对应的bean注册到工厂上

//---------------------------------------------------------------------
// Implementation of BeanDefinitionRegistry interface
//---------------------------------------------------------------------

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
		throws BeanDefinitionStoreException {

	Assert.hasText(beanName, "Bean name must not be empty");
	Assert.notNull(beanDefinition, "BeanDefinition must not be null");

	if (beanDefinition instanceof AbstractBeanDefinition) {
		try {
			// bean的验证
			((AbstractBeanDefinition) beanDefinition).validate();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
					"Validation of bean definition failed", ex);
		}
	}

	// ConcurrentHashMap中获取持有对象
 	// Spring是拿beanname 做key 持有对象做value 将数据存在 ConcurrentHashMap中
 	// 1.5 之前用的HashMap
	BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
	// 判断是否存在同id的BeanDefinition 
	if (existingDefinition != null) {
		// 允许Bean定义重写吗
		if (!isAllowBeanDefinitionOverriding()) {
			throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
		}
		else if (existingDefinition.getRole() < beanDefinition.getRole()) {
			// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
			if (logger.isInfoEnabled()) {
				logger.info("Overriding user-defined bean definition for bean '" + beanName +
						"' with a framework-generated bean definition: replacing [" +
						existingDefinition + "] with [" + beanDefinition + "]");
			}
		}
		// 若已存在的和需要装配的bean不同
		else if (!beanDefinition.equals(existingDefinition)) {
			if (logger.isDebugEnabled()) {
				logger.debug("Overriding bean definition for bean '" + beanName +
						"' with a different definition: replacing [" + existingDefinition +
						"] with [" + beanDefinition + "]");
			}
		}
		else {
			if (logger.isTraceEnabled()) {
				logger.trace("Overriding bean definition for bean '" + beanName +
						"' with an equivalent definition: replacing [" + existingDefinition +
						"] with [" + beanDefinition + "]");
			}
		}
		// 如果不存在上述情况 加载到工厂当中(id做key,beanDefinition做value)
		this.beanDefinitionMap.put(beanName, beanDefinition);
	}
	// 不存在
	else {
		// 检查工厂的bean创建阶段是否已经开始,即是否有bean被标记为已创建。
		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;
				removeManualSingletonName(beanName);
			}
		}
		else {
			// Still in startup registration phase
			this.beanDefinitionMap.put(beanName, beanDefinition);
			this.beanDefinitionNames.add(beanName);
			removeManualSingletonName(beanName);
		}
		this.frozenBeanDefinitionNames = null;
	}

	if (existingDefinition != null || containsSingleton(beanName)) {
		resetBeanDefinition(beanName);
	}
	else if (isConfigurationFrozen()) {
		clearByTypeCache();
	}
}

该beanDefinitionMap是DefaultListableBeanFactory工厂的一个属性。此时将bean的唯一id做key ,解析bean BeanDefinition 做value 存储的工厂当中当中
在这里插入图片描述
此时我们将Spring读取的资源放到DefaultListableBeanFactory工厂中的底层源码流程解析完毕。

Spring Bean实例的注册流程总结

  • 1.定义好Spring的配置文件。
  • 2.通过Resource对象奖Spring配置文件进行抽象,抽象成一个具体的Resource对象(如ClassPathResource)。
  • 3.定义好将要使用的Bean工厂(各种BeanFactory)。
  • 4.定义好XmlBeanDefinitionReader对象,并将工厂对象作为参数传递进去,从而构建好二者之间的关联关系。
  • 5.通过XmlBeanDefinitionReader对象读取之前所抽取出的Resource对象。
  • 6.流程开始进行解析。
  • 7.针对XML文件进行各种元素以及元素属性的解析,这里面,真正的解析是通过BeanDefinitionParserDelegate对象来完成的(委托模式)
  • 8.通过BeanDefinitionParserDelegate对象在解析XML文件时,又使用到了模版方法设计模式(pre,process,post)。
  • 9.当所有的bean标签元素都解析完毕后,开始定义一个BeanDefinition对象,该对象是一个非常重要的对象,里面容纳了一个Bean相关的所有属性。
  • 10.BeanDefinition对象创建完毕后,Spring又会创建一个BeanDefinitionHolder对象来持有这个BeanDefinition对象。
  • 11.BeanDefinitionHolder对象主要包含俩部分内容:beanName与BeanDefinition。
  • 12.工厂会将解析出来的Bean信息存放到内部的一个ConcurrentHashMap中,该Map的键是beanName(唯一),值是BeanDefinition对象。
  • 13.调用Bean解析完毕的触发动作,从而触发相应的监听器的方法的执行(使用了观察者模式)。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值