转载

springIOC源码深度解析

以前没有意识到阅读优秀框架源码的重要性,直到我阅读完mybatis、spring IOC、AOP, springMVC的源码,从中学了不少底层的知识,比如java的反射内省,jdk动态代理,cglib动态代理,体会到源码中使用了各种设计模式,使得框架具有非常强大的扩展性,那个时候我才发现框架也是很美的。废话不多说,下面开始我们的SpringIOC源码之旅。

本文采用的源码版本是5.2.x。为了我们更好地理解springIOC,我们使用的是xml的方式,实际开发中大部分都是是用注解的方式,经验告诉我,从理解源码的角度上来讲,xml配置是最好不过了。

阅读源码的建议:去spring官网下载最新的源码,对照着看,不然根本看不下去,之前我就吃过亏,自以为看书就能把源码弄明白,当时真是太天真了,看了几页就放弃了,因为根本就看不懂。

本文假定读者已经有spring相关的使用基础,比如如何建立工程,引入spring相关的依赖,并会使用单元测试。

引言

阅读源码最大的难点就是入口难找,经验告诉我们,我们平时使用到的源码方式就是阅读的入口,这和我们平时开发都是息息相关的。

建一个maven工程,添加相关依赖,使用单元测试来测试获取bean的流程。

下面我们来看看我们平时都是怎么使用的springIOC:

下面是我们平时获取一个bean的原始方式:

public class TestSpring {
    @Test
    public void testSpring() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("application.xml");
        Student student = (Student) ctx.getBean("student");
        System.out.println(student);
    }
}
复制代码

在resource文件夹下新建一个application.xml文件,通常叫 application.xml 或 application-xxx.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" xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
    <bean id="student" class="com.sjc.spring.po.Student">
        <!-- String类型 -->
        <property name="name" value="jiangcong"></property>
        <!-- Integer类型 -->
        <property name="age" value="18"></property>
        <!-- 引用类型 -->
        <property name="course" ref="course"></property>
    </bean>

    <!-- 该类有一个初始化方法 -->
    <bean id="course" class="com.sjc.spring.po.Course"
          init-method="init">
        <!-- String类型 -->
        <property name="name" value="spring"></property>
    </bean>
</beans>

复制代码

Student类

public class Student {

	private String name;
	private Integer age;

	private Course course;
  //... 省略getter/setter方法
}
复制代码

Course类

public class Course {

	private String name;
	//... 省略getter/setter方法
}
复制代码

例子很简单,但是也够引出本文的主题了,探索spring容器如何加装配置文件,以及如何为我们实例化bean,使得我们通过getBean("student")就可以获取到一个Student类的实例,从而理解spring中核心的IOC、DI。

开始阅读源码之前,先介绍一下Spring重要的接口,这里不要求大家掌握,只是到时候进入源码阅读部分时候,脑子里有个印象,再来查找这部分的知识就好了。

Spring重要接口介绍

BeanFactory继承体系

springIOC源码深度解析

看到这些错综复杂的类关系图,我们不禁感慨,spring的庞大。那么spring为啥要定义这么多接口呢?因为每个接口都有它使用的场合,各个接口之间具有一定的职责,但是又互不干扰,这就是设计模式中的接口隔离原则。你就想一下,如果把这些功能全都在一两个接口实现,那且不是乱成一团糟。

下面介绍主要类的主要功能:

BeanFactory:

接口主要定义了IOC容器的基本行为,比如根据各种条件获取Bean。这里使用了工厂模式。

ListableBeanFactory:

从名字可以看出来,这个接口的特点就是可以生产实例列表,比如根据类型获取Bean实例获取的是列表Bean实例

HierarchicalBeanFactory:

主要是实现了Bean工厂的分层。

AutowireCapableBeanFactory:

自动装配的Bean工厂

这个工厂接口继承自BeanFacotory,它扩展了自动装配的功能,根据类定义BeanDefinition装配 Bean、执行前、后处理器等。

ConfigurableBeanFactory

复杂的配置Bean工厂

ConfigurableListableBeanFactory

这个类非常之庞大,这个工厂接口总共有83个接口,包含了BeanFactory体系目前的所有方法。

BeanDefinitionRegistry

用来操作定义在工厂内部的BeanDefinition对象。比如注册BeanDefinition获取BeanDefinition

BeanDefinition继承体系

springIOC源码深度解析

ApplicationContext继承体系

springIOC源码深度解析

源码解析篇

创建IOC容器

介绍完了主要的接口,我们进入源码分析

分析入口是: AbstractApplication#refresh()

整个容器初始化流程大体可以分为12步,想对哪一步骤感兴趣的读者可以自行决定将其作为分支入口了解其原理。这里我分析第2步和第11步,也就是IOC最关键的流程:创建BeanFactory的流程和Bean初始化的流程。为了省略篇幅,省略掉了相关干扰项,比如try/catch块。

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			// 1: 刷新预处理
			// 设置Spring容器的启动时间,撤销关闭状态,开启活跃状态。
			// 初始化属性源信息(Property)
			// 验证环境信息里一些必须存在的属性
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			// 2:
			// a) 创建IOC容器(DefaultListableBeanFactory)
			// b) 加载解析XML文件(最终存储到Document对象中)
			// c) 读取Document对象,并完成BeanDefinition的加载和注册工作
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			// 3: 对IOC容器做一些预处理(设置一些公共属性)
			prepareBeanFactory(beanFactory);

				// 4:
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// 5:调用BeanFactoryPostProcessor后置处理器对BeanDefinition处理
				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				// 6: 注册BeanPostProcessor后置处理器
				registerBeanPostProcessors(beanFactory);

				// 7: 初始化一些消息源(比如处理国际化的i18n等消息资源)
				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				// 8: 初始化应用事件广播器
				initApplicationEventMulticaster();

				// 9:初始化一些特殊的bean
				// Initialize other special beans in specific context subclasses.
				onRefresh();
				// 10:注册一些监听器
				// Check for listener beans and register them.
				registerListeners();
				// 11:实例化剩余的单例bean(非懒加载方式)
				// 注意事项: Bean的IOC、ID和AOP都是发生在此步骤
				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);
				// 12: 完成刷新时,需要发布对应的事件
				// Last step: publish corresponding event.
				finishRefresh();
		}
		//...省略try/catch代码块
		
复制代码

我们跟进第2步obtainFreshBeanFactory(),这里主要完成XML文件的解析(最终存储到Document对象中),读取Document对象,并完成BeanDefinition的加载和注册工作,返回一个Bean工厂DefaultListableBeanFactory,读者的可以对照着上面的UML类关系图,找到DefaultListableBeanFactory的位置,体会一下这个类的作用。

我们接着进入到AbstractRefreshableApplicationContext#refreshBeanFactory

这里就会创建一个比较重要的容器IOC容器工厂,DefaultListableBeanFactory,我们配置文件的信息就以BeanDefinition对象形式存放在这里,我们关注loadBeanDefinitions(beanFactory);这行代码,这里就是加载我们的配置文件封装到BeanDefinition并存到DefaultListableBeanFactory的逻辑实现,这里只是定义了一个钩子方法,实现主要由子类去实现,有点像设计模式中的抽象模板方法。

protected final void refreshBeanFactory() throws BeansException {
		// 如果之前有IOC容器,则销毁
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
    // 创建IOC容器,也就是DefaultListableBeanFactory
    DefaultListableBeanFactory beanFactory = createBeanFactory();
    beanFactory.setSerializationId(getId());
    // 设置工厂的属性:是否允许BeanDefinition覆盖和是否允许循环依赖
    customizeBeanFactory(beanFactory);
    // 调用BeanDefinition的方法,在当前类中定义了抽象的loadBeanDefinitions方法,具体的实现调用子类容器。
    loadBeanDefinitions(beanFactory); // 钩子方法
    synchronized (this.beanFactoryMonitor) {
    this.beanFactory = beanFactory;
    }
    //...省略try/catch代码块
	}
复制代码

这里我们主要关心xml配置文件对应的实现类,也有注解的形式,感兴趣的读者可以将此作为分支进行深入研究。

我们进到 AbstractXmlApplicationContext#loadBeanDefinitions

这里我们看到了接口隔离设计原则和单一职责原则,初步体会到了定义这么多的接口的好处。我们先来看BeanFactory的继承体系中, DefaultListableBeanFactory是实现了BeanDefinitionRegistry接口,拥有了注册BeanDefinition的能力,但这里传给XmlBeanDefinitionReader这个BeanDefinition阅读器的只是将BeanDefinitionRegistry这个拥有注册BeanDefinition功能接口传入(我们看XmlBeanDefinitionReader构造函数就知道,public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) ),其他的能力还在DefaultListableBeanFactory中,这其实是保护了DefaultListableBeanFactory,体现了接口隔离的效果。

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		// 创建一个BeanDefinition阅读器,通过阅读XML文件,真正完成BeanDefinition的加载和注册
		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);
		// 委托给BeanDefinitions阅读器去加载BeanDefinition
		loadBeanDefinitions(beanDefinitionReader);
	}
复制代码

我们接着进入到loadBeanDefinitions方法中,

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
		// 获取资源的定位
		// 这里getConfigResources是一个空实现,真正实现是调用子类的获取资源定位的方法
		// 比如:ClassPathXmlApplicationContext中进行了实现
		// 		而FileSystemXmlApplicationContext没有使用该方法
		Resource[] configResources = getConfigResources();
		if (configResources != null) {
			// XML Bean读取器调用其父类AbstractBeanDefinitionReader读取定位的资源
			reader.loadBeanDefinitions(configResources);
		}
		// 如果子类中获取的资源定位为空,则获取FileSystemXmlApplicationContext构造方法中setConfigLocations方法设置的资源
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			// XML Bean读取器调用其父类AbstractBeanDefinitionReader读取定位的资源
			reader.loadBeanDefinitions(configLocations);
		}
	}
复制代码

这里我们主要看

reader.loadBeanDefinitions(configLocations),并进入到

public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
		// 获取在IOC容器初始化过程中设置的资源加载器
		ResourceLoader resourceLoader = getResourceLoader();
		if (resourceLoader == null) {
			throw new BeanDefinitionStoreException(
					"Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
		}

		if (resourceLoader instanceof ResourcePatternResolver) {
			// Resource pattern matching available.
				Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
				// 委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能
				int count = loadBeanDefinitions(resources);
				if (actualResources != null) {
					Collections.addAll(actualResources, resources);
				}
				if (logger.isTraceEnabled()) {
					logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
				}
				return count;
			}
			// ...省略try/catch代码块
}
复制代码

我们进入到其子类XmlBeanDefinitionReader#loadBeanDefinitions

这里会获取XML文件的InputStream流,并封装到InputSource中,我们主要看doLoadBeanDefinitions这个具体的解析过程。

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		 //...省略若干代码
			// 将资源文件转为InputStream的IO流
			InputStream inputStream = encodedResource.getResource().getInputStream();
				// 从InputStream中得到XML的解析流
				InputSource inputSource = new InputSource(inputStream);
				if (encodedResource.getEncoding() != null) {
					inputSource.setEncoding(encodedResource.getEncoding());
				}
				// 具体的解析过程
				return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
			}
			//...省略try/catch代码块
			
	}
复制代码

我们来到XmlBeanDefinitionReader#doLoadBeanDefinitions:

这里主要是将XML封装成Document对象,然后对Document对象的解析操作,完成BeanDefinition的加载和注册工作。经过千辛万苦,我们终于来到这一步,不容易啊!

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {

			// 通过DOM4加载解析XML文件,最终形成Document对象
			Document doc = doLoadDocument(inputSource, resource);
			// 通过对Document对象的解析操作,完成BeanDefinition的加载和注册工作
			int count = registerBeanDefinitions(doc, resource);
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + count + " bean definitions from " + resource);
			}
			return count;
			// .../省略try/catch代码块

复制代码

我们来看看BeanDefinition是如何注册的

进入到XmlBeanDefinitionReader#registerBeanDefinitions

这里 很好地利用了面向对象中单一职责原则,将逻辑处理委托给单一的类进行处理,比如: BeanDefinitionDocumentReader

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		// 使用DefaultBeanDefinitionDocumentReader实例化BeanDefinitionDocumentReader
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		// 记录统计前BeanDefinition的加载个数
		int countBefore = getRegistry().getBeanDefinitionCount();
		// 加载及注册bean
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		// 记录本次加载的BeanDefinition个数
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}
复制代码

我们进入到BeanDefinitionDocumentReader#registerBeanDefinitions

并进入到其默认实现类DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions

protected void doRegisterBeanDefinitions(Element root) {
		// 这里使用了委托模式,将具体的BeanDefinition解析工作交给了BeanDefinitionParserDelegate去完成
		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(getReaderContext(), root, parent);

		//...省略掉了默认命名空间的代码
		// 在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性
		preProcessXml(root); // 钩子方法
		// 委托给BeanDefinitionParserDelegate,从Document的根元素开始进行BeanDefinition的解析
		parseBeanDefinitions(root, this.delegate);
		// 在解析Bean定义之后,进行自定义的解析,增加解析过程的可扩展性
		postProcessXml(root); // 钩子方法

		this.delegate = parent;
	}
复制代码

这里我们主要关心parseBeanDefinitions

进入到DefaultBeanDefinitionDocumentReader#parseBeanDefinitions

这里就比较重要了,遍历解析Document对象的所有子节点,这里我们只关心parseDefaultElement,也就是 bean标签、import标签、alias标签,则使用默认解析规则

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		// 加载的Document对象是否使用了Spring默认的XML命名空间(beans命名空间)
		if (delegate.isDefaultNamespace(root)) {
			// 获取Document对象根元素的所有子节点(bean标签、import标签、alias标签和其他自定义标签context、aop等)
			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;
					// bean标签、import标签、alias标签,则使用默认解析规则
					if (delegate.isDefaultNamespace(ele)) {
						parseDefaultElement(ele, delegate);
					}
					else { //像context标签、aop标签、tx标签,则使用用户自定义的解析规则解析元素节点
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			delegate.parseCustomElement(root);
		}
	}
复制代码

我们进入到DefaultBeanDefinitionDocumentReader#parseDefaultElement

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		// 解析<import>标签
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		// 解析<alias>标签
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
		// 解析bean标签
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			// 递归调用
			doRegisterBeanDefinitions(ele);
		}
	}
复制代码

这里我们主要看标签的解析,其他的读者感兴趣的话可以自己去看。

我们进入到DefaultBeanDefinitionDocumentReader#processBeanDefinition

BeanDefinitionParserDelegate#parseBeanDefinitionElement会解析BeanDefinition,并封装到BeanDefinitionHolder,

BeanDefinitionReaderUtils#registerBeanDefinition会最终将BeanDefinition注册到BeanDefinitionRegistry(DefaultListableBeanFactory)中,并存入到map中:private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

感兴趣的读者可以继续跟踪,这里我们终于解析完了BeanDefinition。完成了AbstractApplicationContext#refresh() 的第2步:XML文件的解析和BeanDefinition的加载和注册工作

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		// 解析<bean>标签,获取BeanDefinition
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// 注册最终的BeanDefinition到BeanDefinitionRegistry(DefaultListableBeanFactory)
				// Register the final decorated instance.
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			// Send registration event.
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}
复制代码

实例化Bean

我们来看看AbstractApplicationContext#refresh()的第11步,这步很重要、很重要、很重要。。。

这里完成了单例Bean的实例化,Bean的IOC、ID和AOP都是发生在这步

AbstractApplicationContext#finishBeanFactoryInitialization

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
//... 省略掉了若干代码
// Instantiate all remaining (non-lazy-init) singletons.
		// 实例化单例bean
		beanFactory.preInstantiateSingletons();
}
复制代码

我们进入到DefaultListableBeanFactory#preInstantiateSingletons

这里先了解一下,BeanFactory和FactoryBean的区别,

  • BeanFactory是spring顶级接口,是spring基础容器,它负责管理bean实例。

  • FactoryBean只是spring容器中被管理的一个bean对象,只是说这个bean它的能力就是产生另外的对象。

  • BeanFactory是一个包容万物的大工厂

  • FactoryBean是一个只能生产指定对象的小工厂,而且这个小工厂还被大工厂给管理。

  • FactoryBean和普通的Bean实例,被Spring管理时,也是区别对待的。通过&前缀来区分FactoryBean和普通的Bean实例

public void preInstantiateSingletons() throws BeansException {
		if (logger.isTraceEnabled()) {
			logger.trace("Pre-instantiating singletons in " + this);
		}

		// Iterate over a copy to allow for init methods which in turn register new bean definitions.
		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		// 触发所有非懒加载方式的单例bean的创建
		for (String beanName : beanNames) {
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				// 如果bean是一个FactoryBean,则走下面的方法
				if (isFactoryBean(beanName)) {
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if (bean instanceof FactoryBean) {
						final FactoryBean<?> factory = (FactoryBean<?>) bean;
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
											((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						}
						else {
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						}
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}
				else { // 普通bean走下面的方法
					getBean(beanName);
				}
			}
		}
		//...省略掉若干代码
}
复制代码

这里我们走的是普通的Bean

进入AbstractBeanFactory#getBean,

并进入到AbstractBeanFactory#doGetBean

这个方法,主要分为两个步骤:

  1. 从缓存中获取单例Bean,如果获取到了就检测,如果获取出来的Bean是FactoryBean,则需要从FactoryBean实例中产生一个对象
  2. 如果没有获取到Bean,则需要通过BeanDefinition来实例化一个Bean返回
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

		// 获取bean的名称
		final String beanName = transformedBeanName(name);
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
		// 从缓存中获取单例bean
		Object sharedInstance = getSingleton(beanName);
		// 如果获取到单例bean,则走下面代码
		if (sharedInstance != null && args == null) {
			if (logger.isTraceEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
			// 如果取出来的Bean实例是FactoryBean的Bean实例,则需要从FactoryBean实例中产生一个对象实例
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		else { // 如果没有获取到单例bean,则走下面代码
			// Fail if we're already creating this bean instance:
			// We're assumably within a circular reference.
			// 如果原型模式的Bean发生循环引用,则直接不处理,直接抛异常
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			//...省略了检测BeanDefinition是否在Factory中的代码

			try {
				// 获取实例化的bean的BeanDefinition对象
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				// 检查该BeanDefinition对象对应的Bean是否是抽象的
				checkMergedBeanDefinition(mbd, beanName, args);
				//...省略检测代码

				// Create bean instance.
				// 如果是单例的Bean,看下面代码
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							// 创建单例Bean的主要方法
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

				else if (mbd.isPrototype()) { // 原型
					//...省略了处理原型模式Bean的分支
				}

				else { 
					//...省略了比如处理request、session级别的bean的分支
		    }

		return (T) bean;
	}
复制代码

我们主要来看这段代码(重要):

这里用到了Java8的lambda表达式

// Create bean instance.
				// 如果是单例的Bean,看下面代码
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							// 创建单例Bean的主要方法
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
复制代码

进入到DefaultSingletonBeanRegistry#getSingleton

这里处理了循环依赖的问题,什么是循环依赖,以及spring如何解决循环依赖,期待我下一篇文章。

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		synchronized (this.singletonObjects) {
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				//...省略检测代码
				// 创建之前,设置一个创建中的标识
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					// 调用匿名内部类获取单例对象
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
	       //...省略catch代码块
				finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
					// 消除对象创建中的标识
					afterSingletonCreation(beanName);
				}
				// 将产生的单例Bean放入缓存中(总共三级缓存)
				if (newSingleton) {
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}
复制代码

上面 singletonObject = singletonFactory.getObject();调用的是lambda表达式中的createBean(beanName, mbd, args)方法。

我们进入到其实现类

AbstractAutowireCapableBeanFactory#createBean

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
      
     //...省略若干代码块
     // 完成Bean实例的创建(实例化、填充属性、初始化)
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
}
复制代码

进入到我们关心的

AbstractAutowireCapableBeanFactory#doCreateBean

这里完成完成Bean实例的创建,包括三个步骤:

  1. 实例化

    默认调用无参构造实例化Bean,构造参数依赖注入就是发生在这个步骤

  2. 属性填充(DI依赖注入发生在此步骤)

    利用反射和内省技术进行属性设置

  3. 初始化(AOP发生在此步骤)

    也是利用反射调用初始化方法比如

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		// bean初始化第一步:默认调用无参构造实例化Bean
		// 构造参数依赖注入,就是发生在这一步
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		// 实例化后的Bean对象
		final Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		//...省略若干代码

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		// 解决循环依赖的关键步骤
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		// 如果需要提前暴露单例Bean,则将该Bean放入三级缓存中
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			// 将刚创建的bean放入三级缓存中singleFactories(key是beanName,value是FactoryBean)
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			// bean初始化第二步: 填充属性(DI依赖注入发生在此步骤)
			// 这里主要分为两种情况:
			// 1.对于非集合类型的属性,直接使用反射和内省机制去进行属性设置
			// 2。对于集合类型的属性,将其属性值解析为目标类型的集合后直接赋值给属性
			populateBean(beanName, mbd, instanceWrapper);
			// bean初始化第三步:调用初始化方法,完成bean的初始化操作(AOP发生在此步骤)
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		//... 省略catch块代码

		//...省略若干代码
		return exposedObject;
	}
复制代码

到这里,SpringIOC容器对Bean定义的资源文件的加载、解析和依赖注入已经解析完毕,现在SpringIOC容器中管理了一系列靠依赖关系联系起来的Bean,程序不需要应用自己手动创建所需对象,SpringIOC容器会在我们使用的时候自动为我们创建,并且为我们注入好相关的依赖,这就是Spring核心功能的控制反转和依赖注入的相关功能,所谓的反转,也就是将创建Bean的权利交给spring进行管理。

原文  https://juejin.im/post/5de8bf9e5188251260742f05
正文到此结束
Loading...