Spring IOC 实现原理

Posted 一叶知秋V

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring IOC 实现原理相关的知识,希望对你有一定的参考价值。

IOC(Inversion of Control)即控制反转,可以说是 Spring 最核心的部分,IOC 是一种思想,使得开发者从繁琐的对象交互中解脱出来,进而专注对象本身,更进一步突出面向对象。了解 IOC,需要先了解下依赖注入(Dependency Inversion,DI)。

依赖注入就是把底层类作为参数传递给上层类,实现上层对下层的 “控制”。

依赖注入的方式:

  • Set 注入;
  • 接口注入;
  • 构造方法注入;
  • 注解注入。

下面看下依赖倒置原则、IOC、依赖注入(DI)、IOC 容器的关系:

正式依赖倒置原则的指导,才有了 IOC 的思路,而实现 IOC 离不开依赖注入(DI)的支撑,Spring 框架基于 IOC 提出了 IOC 容器的概念。对于 IOC 来说,最重要的就是容器了,容器管理着 Bean 的生命周期,控制着 Bean 依赖注入。

IOC 容器的优势:

  • 避免在各处使用 new 来创建类,并且可以做到统一维护。

下面来看下 Spring IOC 容器。

Spring 启动的时候,会读取应用程序提供的 Bean 配置信息(XML Config、Java Config、注解 @Autowired),并在 Spring 容器中生成一份 Bean 定义注册表,然后根据这张注册表去实例化 Bean,装配好 Bean 之间的依赖关系,为上层提供准备就绪的运行环境。

Spring 提供一个配置文件描述 Bean 之间的依赖关系,利用 Java 语言的反射功能,实例化 Bean,并建立 Bean 之间的依赖关系。

Spring IOC 支持以下功能:

  • 依赖注入;
  • 依赖检查;
  • 自动装配;
  • 支持集合;
  • 指定初始化方法和销毁方法;
  • 支持回调方法(需要实现 Spring 接口,略带侵入性,谨慎使用)。

Spring IOC 容器的核心接口:

  • BeanFactory;
  • ApplicationContext。

为了进一步分析 BeanFactory 和 ApplicationContext,需要先弄清楚 BeanDefinition 接口:

BeanDefinition 接口主要是用来描述 Bean 的定义的。

<!-- 事务配置 -->
<bean id="transactionManager"
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="mobileDataSource"/>
</bean>
@Service
public class MyService 
    @Autowired
    private ConnectionSettings connection;
    //...

Spring 容器在启动的时候,会将 XML Config、Java Config 或者注解里的 Bean 的定义解析成 Spring 内部的 BeanDefinition。

第二个需要了解的是 BeanDefinitionRegistry 接口,BeanDefinitionRegistry 接口提供了向 IOC 容器注册 BeanDefinition 对象的方法。

BeanFactory 是 Spring 框架最核心的接口,它提供了 IOC 的配置机制,包含了 Bean 的各种定义,便于实例化 Bean,BeanFactory 实例化 Bean 的时候会建立 Bean 之间的依赖关系。除此之外,BeanFactory 还包含了 Bean 生命周期的控制。

package org.springframework.beans.factory;
public interface BeanFactory 
    Object getBean(String name) throws BeansException;
    boolean containsBean(String name);
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
    // 省略部分代码...

由于 BeanFactory 的功能还不够强大,所以 Spring 在 BeanFactory 的基础上还设计了一个更为高级的接口 ApplicationContext,ApplicationContext 是 BeanFactory 的子接口之一。

package org.springframework.context;
import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.core.env.EnvironmentCapable;
import org.springframework.core.io.support.ResourcePatternResolver;

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory,
		HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver 
	String getApplicationName();
	ApplicationContext getParent();
	// 省略部分代码...

package org.springframework.beans.factory;
public interface ListableBeanFactory extends BeanFactory 
    boolean containsBeanDefinition(String beanName);
    int getBeanDefinitionCount();
    String[] getBeanDefinitionNames();
    // 省略部分代码...

BeanFactory 和 ApplicationContext 的比较:

  • BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身;
  • ApplicationContext 面向使用 Spring 框架的开发者;
  • BeanFactory 可以理解为 “发动机”,而 ApplicationContext 可以理解为 “汽车”。

ApplicationContext 的功能:

  • 继承 BeanFactory 接口:能够管理、装配 Bean;
  • 继承 ResourcePatternResolver 接口:能够加载资源文件;
  • 继承 MessageSource 接口:能够实现国际化等功能;
  • 继承 ApplicationEventPublisher 接口:能够注册监听器,实现监听机制。

Java Config 中,使用注解 @Configuration 可以将 @Bean 注解的方法返回的实例注入到 Spring IOC 容器中。

@Configuration
public class ApplicationConfig 
    @Bean(name = "person")
    public Person initPerson() 
        return new Person(100L, "Jack"); // id, name
    

Bean 注入的原理?

下来分析一下容器的创建、配置和 getBean() 两个源码。

Spring IOC 容器创建好之后就会调用 refresh() 方法。

  1. Spring IOC 的 refresh() 源码解析

AbstractApplicationContext 是 ApplicationContext 接口的实现类。

package org.springframework.context.support;
public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext, DisposableBean 
    @Override
    public void refresh() throws BeansException, IllegalStateException 
        synchronized (this.startupShutdownMonitor) 
            // 准备刷新上下文
            prepareRefresh();
            // 获取BeanFactory实例
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
            // 对BeanFactory进行相关设置(设置ClassLoader用来加载Bean、设置表达式解析器等), 为后续使用做准备
            prepareBeanFactory(beanFactory);
            try 
                // 在BeanFactory进行相关设置后需要做的逻辑, 方法体为空, 不同的Spring容器会重写它
                postProcessBeanFactory(beanFactory);
                // 这个方法比较重要, 调用工厂后处理器, 处理各类Bean标签, 扫描Bean文件, 并解析成一个个的Bean
                invokeBeanFactoryPostProcessors(beanFactory);
                // 注册实现了BeanPostProcessors接口的Bean
                registerBeanPostProcessors(beanFactory);
                // 初始化国际化相关属性
                initMessageSource();
                // 初始化事件广播器, 事件广播器用于事件发布
                initApplicationEventMulticaster();
                // 模板方法, 方法体为空, 不同的Spring容器会重写它
                onRefresh();
                // 注册事件监听器
                registerListeners();
                // 实例化所有已经被注册但未被实例化的Bean(排除懒加载Bean)
                finishBeanFactoryInitialization(beanFactory);
                // 做一些初始化生命周期处理器等事情
                finishRefresh();
             catch (BeansException ex) 
                if (logger.isWarnEnabled()) 
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                
                destroyBeans();
                cancelRefresh(ex);
                throw ex;
             finally 
                resetCommonCaches();
            
        
    
    // 省略部分代码...

refresh() 方法:

  • 为 IOC 容器以及 Bean 的生命周期管理提供条件;
  • 刷新 Spring 上下文信息,定义整个 Spring 上下文加载的流程。
  1. Spring IOC 的 getBean() 源码解析

AbstractBeanFactory 是 BeanFactory 接口的实现类。

package org.springframework.beans.factory.support;
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory 
    @Override
	public Object getBean(String name) throws BeansException 
		return doGetBean(name, null, null, false);
	
	protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException 
		// 获取beanName
		final String beanName = transformedBeanName(name);
		Object bean;
		// 根据beanName获取共享的实例
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) 
			// 尝试从缓存或者实例工厂中获取实例
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		 else 
			if (isPrototypeCurrentlyInCreation(beanName))  throw new BeanCurrentlyInCreationException(beanName); 
			// 尝试从ParentBeanFactory中获取Bean实例
			BeanFactory parentBeanFactory = getParentBeanFactory();
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) 
				//...
			
			if (!typeCheckOnly)  markBeanAsCreated(beanName); 
			try 
				// 将父类的属性合并到子类里
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);
				// 获取依赖关系
				String[] dependsOn = mbd.getDependsOn();
				// 如果存在依赖, 递归实例化依赖的Bean
				if (dependsOn != null) 
					for (String dep : dependsOn)  //...
					
				
				// 判断Bean的作用域是否是单例的, 如果是单例就去看先前有没有创建过这个Bean, 如果有就直接返回, 没有就创建一个
				if (mbd.isSingleton()) 
					//...
				 else if (mbd.isPrototype())  // 如果作用域是Prototype, 就new一个Bean实例出来
					//...
				 else  //...
				
			 catch (BeansException ex) 
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			
		
		// 类型检查
		if (requiredType != null && !requiredType.isInstance(bean)) 
			//...
		
		return (T) bean;
	
	protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) 
		//...
		Object object = null;
		if (mbd == null) 
		    // 从缓存中获取实例
			object = getCachedObjectForFactoryBean(beanName);
		
		if (object == null) 
			//...
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			// 从实例工厂中获取实例
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		
		return object;
	

getBean() 方法的代码逻辑:

  • 转换 beanName;
  • 尝试从缓存中加载实例;
  • 实例化Bean;
  • 检查 parentBeanFactory;
  • 初始化依赖的 Bean;
  • 创建 Bean。

下面看两个常见的面试问题:

  1. Spring Bean 的作用域?
  • singleton:Spring 的默认作用域,容器里拥有唯一的 Bean 实例;
  • prototype:针对每个 getBean() 请求,容器都会创建一个 Bean 实例;

如果是 Web 容器,还支持以下三种作用域:

  • request:会为每个 http 请求创建一个 Bean 实例;
  • session:会为每个 session 创建一个 Bean 实例;
  • globalSession:会为每个全局 http session 创建一个 Bean 实例,该作用域仅对 Portlet 有效。
  1. Spring Bean 的生命周期?

容器创建之后会解析并创建出来 Bean,Spring Bean 的生命周期是由容器来管理的。

Bean 创建的过程:

  • 实例化 Bean;
  • Aware (注入 Bean ID、BeanFactory 和 AppCtx),Aware 接口是为了能够感知到自身的属性;
  • 调用 BeanPostProcessor 的前置初始化方法 postProcessBeforeInitialization();
  • 如果实现了 InitializingBean 接口,则会调用 InitializingBean 的 afterPropertiesSet() 方法,做一些属性被自定义后的事情;
  • 调用 Bean 自身定义的 init() 方法;
  • 调用 BeanPostProcessor 的后置初始化方法 postProcessAfterInitialization();
  • Bean 的初始化完毕。

Bean 销毁的过程:

  • 如果 Bean 实现了 DisposableBean 接口,则会调用 destroy() 方法;
  • 如果Bean 自身定义了 destroy-method 属性,则会调用其定义的销毁方法;
  • Bean 的销毁完毕。

#2.AOP原理

以上是关于Spring IOC 实现原理的主要内容,如果未能解决你的问题,请参考以下文章

spring的原理是啥?

java编程,spring里ioc和aop用啥原理实现的

整理:Spring IOC 实现原理

Spring IOC 之 SmartInitializingSingleton

Spring框架IOC和AOP的实现原理

Spring框架IOC和AOP的实现原理