Open Source, Open Future!
  menu
107 文章
ღゝ◡╹)ノ❤️

spring 置顶!

IOC

简介

全称:Inversion of Control(控制反转)

当需要一个对象时(比如苹果),有以下两种方式:

  • 传统方式

image.png

需要主动去创建对象,是一个主动行为。

  • IOC方式

image.png

对象由IOC容器创建,然后在需要的地方注入;由原来的主动获取转变成了被动接收。

容器

简介

Spring的容器设计中,主要有以下两个系列:

容器说明
BeanFactory简单容器,实现了容器最基本的功能
ApplicationContext高级容器,在简单容器基础上增加了很多特性

主要接口设计如下:

image.png

1、第一条设计主线(黄色)
以BeanFactory接口为核心,定义了容器的基本功能。

2、第二条设计主线(红色)
以ApplicationContext接口为核心,添加了很多高级容器的特性。

BeanFactory

简单容器,实现了容器最基本的功能。

API 如下:

image.png

类图(部分)如下:

image.png

BeanFactory 有 3 个直接子接口,最终默认实现类为:DefaultListableBeanFactoryDefaultListableBeanFactory实现了基本容器的所有功能,它是一个很重要的类,很多其他容器都是在它的基础上做的扩展。

ApplicationContext

高级容器,在简单容器基础上增加了很多特性。

类图(部分)如下:

image.png

  • 继承自BeanFactory,所以拥有简单容器的所有功能;
  • MessageSource:对国际化提供支持;
  • ApplicationEventPublisher:提供事件机制;
  • ResourceLoader:可以用来加载多个 Resource,可以灵活访问不同的资源;
  • 对 Web 应用的支持;

重要接口说明

Resource

对各种形式的资源提供了统一接口,针对不同的使用场景有不同的实现;比如文件系统的bean定义使用FileSystemResource,类路径下的bean定义使用ClassPathResource等。

类图(部分)如下:

image.png

说明
FileSystemResource文件系统资源
ClassPathResource类路径下的资源
ByteArrayResource二进制数组资源
InputStreamResource输入流资源
ServletContextResourceWeb容器中的资源
UrlResourceURL表示的资源
ResourceLoader

资源加载器。

类图(部分)如下:

image.png

说明
FileSystemResourceLoader从文件系统加载资源
ResourcePatternResolver通配符加载多个资源
MessageSource

对国际化信息访问提供支持。

MessageSource

类图(部分)如下:

image.png

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);
    }

简要说明:

  1. ClassPathResource:表示spring需要在类路径中寻找资源
  2. DefaultListableBeanFactory:这是一个最基础的容器
  3. 创建读取器;
  4. 读取资源,解析为BeanDefinition,并注册进容器中。
  5. 获取bean实例。

整个过程主要分为两步:

  1. 容器初始化(前4步)
  2. 依赖注入(第一次使用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);
    }

简单容器初始化

初始化过程主要分为以下三步:

  1. Resource的定位
  2. BeanDefinition的载入
  3. BeanDefinition的注册

主要逻辑在loadBeanDefinitions方法中,时序图如下:

image.png

说明:
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));
		}
	}

流程大致分为三步:

  1. 将元素解析为BeanDefinition
  2. BeanDefinition向容器注册;
  3. 注册完成后发布事件。

时序图如下:

image.png

说明:
1 ~ 6: 将元素解析为BeanDefinition,用BeanDefinitionHolder(内部有字段:beanNamealiasesbeanDefinition)做封装;
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

时序图如下:

image.png

说明:

  • 1:从AbstractBeanFactory继承的方法;先从缓存中查询bean,若能查到直接返回;查不到则进行第2步;
  • 2:使用单例模式创建bean(spring默认使用singleton模式,此外还有prototyperequestsession 模式);
  • 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:调用所有的后置处理器;
  • 12:单例bean创建后的逻辑;
  • 13:将生成的单例bean加入缓存中;
第二次调用getBean

时序图如下:

image.png

说明:

  • 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;
    }

相关信息如下:

变量类型说明
singletonObjectsConcurrentHashMapbeanName ---> bean instance
earlySingletonObjectsHashMapbeanName ---> bean instance(这里的 bean 不是完整的)
singletonFactoriesHashMapbeanName ---> ObjectFactory
singletonsCurrentlyInCreationSet当前正在创建中的beansname集合
  • getObjectForBeanInstance: 如果bean的类型为FactoryBean,则需要在这里作进一步处理;先在factoryBeanObjectCache中查询,若没有,则调用getObject方法返回bean实例。(FactoryBean

相关信息如下:

变量类型说明
factoryBeanObjectCacheConcurrentHashMapfactoryBean name ---> bean instance
简单总结
  1. 获取bean时,先从缓存中取;
    1.1. 若有,判断是否是FactoryBean类型,不是则直接返回bean,若是调用getObject方法返回bean
    1.2. 若没有,则从父容器查询,依次向上查,能查到直接返回;否则进行下一步;

  2. 检查bean有没有依赖其他bean(对应depends-on属性),若有则先完成这些bean的实例化;

  3. 实例化当前bean

  4. 属性填充;

  5. bean初始化;

  6. 将生成的单例bean加入缓存中;

高级容器初始化

主要逻辑在refresh方法中,时序图如下:

image.png

说明:

  • 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生命周期

image.png

详情见:spring---bean生命周期

循环依赖

详情见:spring---循环依赖

事件

注解

AOP

事务

相关链接

中文文档
spring教程