Spring概述

前言

Spring 发展至现在,俨然成为一个生态,但要理解其余的 Spring Boot、Spring Cloud 等框架,需要先对 Spring 的整个体系有一定的理解,因为其余的框架都是在 Spring 框架的基础上进行的扩展,当理解了 Spring 的核心之后其余的框架就很容易搞明白了,Spring 的核心在于 IOC 和 BeanDefinition,IOC容器用于存放所有的单例 Bean 和所创建单例 Bean 所需要的 BeanDefinition,其余的 AOP、事务等全部都是在此基础上进行的扩展。

此系列可能会将整体混合书写,比如:在进行 Spring 分析的时候,可能会插入一些 Spring Boot 的解析,也有可能会插入别的知识点,但大部分都不会脱离 Spring 源码的主线。

XML 的方式属于 Spring 的原生使用方式,在后期的时候扩展出了注解方式的处理,文章会从 xml 方式开始,中间会穿插注解的处理方式。其余的很多东西,大家都能在网上查到响应的资料,这里就不再过多的说明。

这里说一下整体的阅读源码的方式吧,Spring 源码前前后后翻了将近 5-6 次,最近才领略到 Spring 的魅力之所在,大致方式为先整体后细分,先全局再部分,先知道大致的一个处理流程,然后再去看其详细的部分,整个系列也是这个方式,会有一个全局的大流程贯穿,然后辅以详细的流程处理,一层一层的去看里面的处理方式。

在进行之前,建议安装一个 Translation 翻译插件,方便进行翻译。

环境搭建问题,这里不再赘述,网上有大量的教程,有问题的话,可以直接进入文章最后的群进行询问。

注意:这里假设是你已经有一定的开发经验了,很多细小的问题,可能没有注意到,如果有什么疑问,可以直接通过评论或者加群询问。

IOC总览

这里的分析主要从 ClassPathXmlApplicationContext 这个类开始,最终会调用到 refresh() 这个方法,整体会从 refresh() 这个方法作为入口进行一系列的分析,其余的 Spring Boot (AnnotationConfigServletWebServerApplicationContext) 框架,等都会调用到这个方法,所以说 refresh() 是核心方法也不为过,所以整体的脉络也不会偏离 refresh() 这个方法。

ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

此处,的 super(parent) 会调用父类的方法,加载资源解析器,

public AbstractApplicationContext() {
    // 创建资源模式处理器,后续在加载 xml 配置文件的时候需要使用到 PathMatchingResourcePatternResolver
    this.resourcePatternResolver = getResourcePatternResolver();
}

setConfigLocations(configLocations)获取系统属性和系统环境变量,对上述路径进行表达式(${})进行解析。

public ClassPathXmlApplicationContext(
    String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
    throws BeansException {
    // 调用父类构造方法,进行相关的对象创建等操作,包含属性的赋值操作
    super(parent);
    setConfigLocations(configLocations);
    if (refresh) {
        refresh();
    }
}

refresh()方法的核心处理

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        	/**
			 * 做容器刷新前的准备工作
			 * 1、设置容器的启动时间
			 * 2、设置活跃状态为true
			 * 3、设置关闭状态为false
			 * 4、获取Environment对象,并加载当前系统的属性值到Environment对象中
			 * 5、准备***和事件的集合对象,默认为空的集合
			 */

        prepareRefresh();

        	/**
			// Tell the subclass to refresh the internal bean factory.
			// 创建容器对象:DefaultListableBeanFactory
			// 加载xml配置文件的属性值到当前工厂中,最重要的就是 BeanDefinition 加载、解析 xml, 形成 GenericBeanDefinition, 自定义标签的解析和默认的 bean 标签解析都在此处,解析自定义标签的时候会将 inner 类注入到 BeanDefinitionMap 中去
			 */
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // Prepare the bean factory for use in this context.
        // beanFactory的准备工作,对各种属性进行填充
        /** 添加一些 BeanPostProcessor,忽略某些接口,添加 SPEL 表达式解析器,注册某些特定的 bean 到 IOC 容器中去*/
        prepareBeanFactory(beanFactory);

        try {
            // Allows post-processing of the bean factory in context subclasses.
            // 子类覆盖方法做额外的处理,此处我们自己一般不做任何扩展工作,但是可以查看web中的代码,是有具体实现的
            postProcessBeanFactory(beanFactory);

            // Invoke factory processors registered as beans in the context.
       /**注册并调用所有的 BFPP 接口,注解的解析就是在此进行,ConfigurationClassPostProcessor 用于解析注解。*/
            invokeBeanFactoryPostProcessors(beanFactory);

            // Register bean processors that intercept bean creation.
            // 注册bean处理器,这里只是注册功能,真正调用的是getBean方法
            registerBeanPostProcessors(beanFactory);

            // Initialize message source for this context.
            // 为上下文初始化message源,即不同语言的消息体,国际化处理,
            initMessageSource();

            // Initialize event multicaster for this context.
            // 初始化事件监听多路广播器
            initApplicationEventMulticaster();

            // Initialize other special beans in specific context subclasses.
            // 留给子类来初始化其他的bean
            onRefresh();

            // Check for listener beans and register them.
            // 在所有注册的bean中查找listener bean,注册到消息广播器中
            registerListeners();

            // Instantiate all remaining (non-lazy-init) singletons.
            // 初始化剩下的单实例(非懒加载的)
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            // 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
            finishRefresh();
        }

        catch (BeansException ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
            }

            // Destroy already created singletons to avoid dangling resources.
            // 为防止bean资源占用,在异常处理中,销毁已经在前面过程中生成的单件bean
            destroyBeans();

            // Reset 'active' flag.
            // 重置active标志
            cancelRefresh(ex);

            // Propagate exception to caller.
            throw ex;
        }

        finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            resetCommonCaches();
        }
    }
}

整体的大致流程图

prepareRefresh()

准备刷新

protected void prepareRefresh() {
		// Switch to active.
		// 设置容器启动的时间
		this.startupDate = System.currentTimeMillis();
		// 容器的关闭标志位
		this.closed.set(false);
		// 容器的激活标志位
		this.active.set(true);

		// 记录日志
		if (logger.isDebugEnabled()) {
			if (logger.isTraceEnabled()) {
				logger.trace("Refreshing " + this);
			}
			else {
				logger.debug("Refreshing " + getDisplayName());
			}
		}

		// Initialize any placeholder property sources in the context environment.
		// 留给子类覆盖,初始化属性资源
		initPropertySources();

		// Validate that all properties marked as required are resolvable:
		// see ConfigurablePropertyResolver#setRequiredProperties
		// 创建并获取环境对象,验证需要的属性文件是否都已经放入环境中
		getEnvironment().validateRequiredProperties();

		// Store pre-refresh ApplicationListeners...
		// 判断刷新前的应用程序***集合是否为空,如果为空,则将***添加到此集合中
		if (this.earlyApplicationListeners == null) {
			this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
		}
		else {
			// Reset local application listeners to pre-refresh state.
			// 如果不等于空,则清空集合元素对象
			this.applicationListeners.clear();
			this.applicationListeners.addAll(this.earlyApplicationListeners);
		}

		// Allow for the collection of early ApplicationEvents,
		// to be published once the multicaster is available...
		// 创建刷新前的监听事件集合
		this.earlyApplicationEvents = new LinkedHashSet<>();
	}