Spring——IOC

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

核心价值是将对象的创建和对象的使用解耦。

了解 IOC,需要先了解下依赖注入(Dependency Inversion,DI)。

依赖注入的方式:

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

Spring 框架基于 IOC 提出了 IOC 容器的概念。对于 IOC 来说,最重要的就是容器了,容器管理着 Bean 的生命周期,控制着 Bean 依赖注入。

Spring 启动的时候,会读取应用程序提供的 Bean 配置信息(XML Config、Java Config、注解 @Autowired),并在 Spring 容器中生成一份 Bean 定义注册表,然后根据这张注册表去实例化 Bean,装配好 Bean 之间的依赖关系,为上层提供准备就绪的运行环境。
在这里插入图片描述
Spring 提供一个配置文件描述 Bean 之间的依赖关系,利用 Java 语言的反射功能,实例化 Bean,并建立 Bean 之间的依赖关系。

Spring IOC 容器的核心接口:

  • BeanFactory;
  • ApplicationContext;

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

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

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 框架的开发者;

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 注入的原理?

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 上下文加载的流程。

2.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。

常见问题

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 的销毁完毕。

Spring Bean的循环依赖?

方式实现
构造注入解决循环依赖创建a,先标记a在创建。构造注入的时候。 a依赖b。 需要得到b的实例去创建a.于是去创建b.标记b正在被创建。
b构造函数注入a。又需要a的实例。又去createBean A 。 标记A 正在被创建。 注意:此时a已经被标记第二次了。 所以报错
setter注入解决循环依赖通过setter注入的时候。是通过无参构造创建的。a,b。
a setb的时候,需要一个b, b被create出来。但是是 b中的成员变量a ,这个a 只是 new a(); 还没有 a.setB()的。 也就是 一个成员变量为空的a
就是注入了一个成员变量为空的bean实例

自己实现IOC?

实现思路:

  1. 提供执行入口:ClassPathXmlApplicationContext:负责组装 BeansFactory 和 BeanConfigParser 两个类,串联执行流程:从 classpath 中加载 XML 格式的配置文件,通过 BeanConfigParser 解析为统一的 BeanDefinition 格式,然后,BeansFactory 根据 BeanDefinition 来创建对象。

  2. 配置文件解析:BeanConfigParser XmlBeanConfigParser负责将配置文件解析为 BeanDefinition 结构,以便 BeansFactory 根据这个结构来创建对象。

  3. 核心工厂类设计:BeansFactory 负责根据从配置文件解析得到的 BeanDefinition 来创建对象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值