IOC
简介
全称:Inversion of Control
(控制反转)
当需要一个对象时(比如苹果),有以下两种方式:
- 传统方式
需要主动去创建对象,是一个主动行为。
- IOC方式
对象由IOC容器创建,然后在需要的地方注入;由原来的主动获取转变成了被动接收。
容器
简介
Spring的容器设计中,主要有以下两个系列:
容器 | 说明 |
---|---|
BeanFactory | 简单容器,实现了容器最基本的功能 |
ApplicationContext | 高级容器,在简单容器基础上增加了很多特性 |
主要接口设计如下:
1、第一条设计主线(黄色)
以BeanFactory接口为核心,定义了容器的基本功能。
2、第二条设计主线(红色)
以ApplicationContext接口为核心,添加了很多高级容器的特性。
BeanFactory
简单容器,实现了容器最基本的功能。
API 如下:
类图(部分)如下:
BeanFactory
有 3 个直接子接口,最终默认实现类为:DefaultListableBeanFactory
;DefaultListableBeanFactory
实现了基本容器的所有功能,它是一个很重要的类,很多其他容器都是在它的基础上做的扩展。
ApplicationContext
高级容器,在简单容器基础上增加了很多特性。
类图(部分)如下:
- 继承自
BeanFactory
,所以拥有简单容器的所有功能; MessageSource
:对国际化提供支持;ApplicationEventPublisher
:提供事件机制;- ResourceLoader:可以用来加载多个 Resource,可以灵活访问不同的资源;
- 对 Web 应用的支持;
重要接口说明
Resource
对各种形式的资源提供了统一接口,针对不同的使用场景有不同的实现;比如文件系统的bean定义使用FileSystemResource
,类路径下的bean定义使用ClassPathResource
等。
类图(部分)如下:
类 | 说明 |
---|---|
FileSystemResource | 文件系统资源 |
ClassPathResource | 类路径下的资源 |
ByteArrayResource | 二进制数组资源 |
InputStreamResource | 输入流资源 |
ServletContextResource | Web容器中的资源 |
UrlResource | URL表示的资源 |
ResourceLoader
资源加载器。
类图(部分)如下:
类 | 说明 |
---|---|
FileSystemResourceLoader | 从文件系统加载资源 |
ResourcePatternResolver | 通配符加载多个资源 |
MessageSource
对国际化信息访问提供支持。
MessageSource
类图(部分)如下:
ApplicationEvent
ApplicationListener
ApplicationEventPublisher
Pointcut
Advice
Advisor
PlatformTransactionManager
示例
从xml文件中获取bean:
<?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="user" class="mncode.User"/>
</beans>
public class User {
}
简单容器测试
@Test
public void test1() {
// 资源
ClassPathResource resource = new ClassPathResource("bean.xml");
// 创建容器
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// 创建读取器
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
// BeanDefinition载入和注册
reader.loadBeanDefinitions(resource);
User user1 = (User) factory.getBean("user");
User user2 = (User) factory.getBean("user");
System.out.println(user1 == user2);
}
简要说明:
ClassPathResource
:表示spring
需要在类路径中寻找资源DefaultListableBeanFactory
:这是一个最基础的容器- 创建读取器;
- 读取资源,解析为
BeanDefinition
,并注册进容器中。 - 获取bean实例。
整个过程主要分为两步:
- 容器初始化(前4步)
- 依赖注入(第一次使用
getBean
时触发)
高级容器测试
@Test
public void test2() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
User user1 = (User) context.getBean("user");
User user2 = (User) context.getBean("user");
System.out.println(user1 == user2);
}
简单容器初始化
初始化过程主要分为以下三步:
Resource
的定位BeanDefinition
的载入BeanDefinition
的注册
主要逻辑在loadBeanDefinitions
方法中,时序图如下:
说明:
2 ~ 6
:读取xml文件,解析为Document
对象;
10
:将Document
对象解析为BeanDefinition
对象,并注册;
第10步parseBeanDefinitions
源码如下:
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
方法(命名空间说明见:spring---xml文件)。
xml文件中的<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);
}
}
这里不同的标签有不同的处理逻辑;其中<bean>
对应的是processBeanDefinition
;
processBeanDefinition
源码如下:
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());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
流程大致分为三步:
- 将元素解析为
BeanDefinition
; - 将
BeanDefinition
向容器注册; - 注册完成后发布事件。
时序图如下:
说明:
1 ~ 6
: 将元素解析为BeanDefinition
,用BeanDefinitionHolder
(内部有字段:beanName
、aliases
、beanDefinition
)做封装;
7 ~ 8
: 注册BeanDefinition
;
DefaultListableBeanFactory
内部维护有下面的字段:
/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
/** List of bean definition names, in registration order. */
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
注册的过程会向上面的结构中添加数据:
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
简单容器依赖注入
对于简单容器来说,依赖注入是在第一次调用getBean
方法时触发的。
第一次调用getBean
时序图如下:
说明:
- 1:从
AbstractBeanFactory
继承的方法;先从缓存中查询bean
,若能查到直接返回;查不到则进行第2
步; - 2:使用单例模式创建
bean
(spring默认使用singleton
模式,此外还有prototype
、request
、session
模式); - 3:单例
bean
创建前的逻辑; - 4:从
AbstractAutowireCapableBeanFactory
继承的方法,创建bean
; - 5:从
BeanDefinition
中解析出对应的 bean 的Class对象; - 6:
bean
实例化之前的逻辑(Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
) ; - 7 ~ 11:真正执行
bean
创建的逻辑 ; - 8:实例化
bean
(默认使用CGLIB生成); - 10:
bean
属性填充; - 11:
bean
初始化;- 11.1:若
bean
实现了*Aware
接口,则调用对应的方法(比如BeanNameAware
,会调用setBeanName
方法); - 11.2:调用所有的前置处理器;
- 11.3:调用初始化方法;
- 11.4:调用所有的后置处理器;
- 11.1:若
- 12:单例
bean
创建后的逻辑; - 13:将生成的单例
bean
加入缓存中;
第二次调用getBean
时序图如下:
说明:
getSingleton
:从缓存中获取bean实例,源码如下:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 从singletonObjects缓存中获取bean
Object singletonObject = this.singletonObjects.get(beanName);
// 若找不到,且bean正在创建中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 加锁
synchronized (this.singletonObjects) {
// 从earlySingletonObjects缓存中获取bean
singletonObject = this.earlySingletonObjects.get(beanName);
// 若找不到,且允许提前使用
if (singletonObject == null && allowEarlyReference) {
// 从singletonFactories缓存中获取对应的ObjectFactory
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 创建bean
singletonObject = singletonFactory.getObject();
// 存入earlySingletonObjects缓存中
this.earlySingletonObjects.put(beanName, singletonObject);
// singletonFactories缓存中移除对应的ObjectFactory
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
相关信息如下:
变量 | 类型 | 说明 |
---|---|---|
singletonObjects | ConcurrentHashMap | beanName ---> bean instance |
earlySingletonObjects | HashMap | beanName ---> bean instance(这里的 bean 不是完整的) |
singletonFactories | HashMap | beanName ---> ObjectFactory |
singletonsCurrentlyInCreation | Set | 当前正在创建中的beans 的name 集合 |
getObjectForBeanInstance
: 如果bean
的类型为FactoryBean
,则需要在这里作进一步处理;先在factoryBeanObjectCache
中查询,若没有,则调用getObject
方法返回bean实例。(FactoryBean)
相关信息如下:
变量 | 类型 | 说明 |
---|---|---|
factoryBeanObjectCache | ConcurrentHashMap | factoryBean name ---> bean instance |
简单总结
-
获取bean时,先从缓存中取;
1.1. 若有,判断是否是FactoryBean
类型,不是则直接返回bean
,若是调用getObject
方法返回bean
;
1.2. 若没有,则从父容器查询,依次向上查,能查到直接返回;否则进行下一步; -
检查
bean
有没有依赖其他bean
(对应depends-on
属性),若有则先完成这些bean
的实例化; -
实例化当前
bean
; -
属性填充;
-
bean
初始化; -
将生成的单例
bean
加入缓存中;
高级容器初始化
主要逻辑在refresh
方法中,时序图如下:
说明:
- 1:上下文刷新之前的准备工作;
- 2:创建容器并初始化;
- 先判断当前上下文中是否已存在容器,存在则销毁;然后创建
DefaultListableBeanFactory
类型的容器(简单容器); - 调用
loadBeanDefinitions
方法初始化(详情见:简单容器初始化);
- 先判断当前上下文中是否已存在容器,存在则销毁;然后创建
- 3:对容器设置(如添加
BeanPostProcessor
等); - 4:
Allows post-processing of the bean factory in context subclasses.
- 5:将所有的
BeanFactoryPostProcessor
处理器注册,并按顺序排序; - 6:将所有的
BeanPostProcessor
处理器注册,并按顺序排序; - 7:初始化上下文中的信息资源;
- 8:初始化上下文中的事件广播器;若不存在则创建一个
SimpleApplicationEventMulticaster
类型的广播器并向上下文注册; - 9:
Initialize other special beans in specific context subclasses.
- 10:注册监听器;
- 11:发布事件:上下文刷新完成;
- 初始化生命周期处理器;若不存在则创建一个
DefaultLifecycleProcessor
类型的处理器并向上下文注册; - 发布事件:上下文刷新完成;
- 初始化生命周期处理器;若不存在则创建一个
高级容器依赖注入
在容器初始化自动完成。
Bean生命周期
循环依赖
详情见:spring---循环依赖