Spring源码入门级学习!!还在对源码疑惑不解?对是否学习源码犹豫不决?这篇文章将带你一探究竟

Spring源码学习

前言

​ 此学习笔记是我个人通过马某人的教学视频进行学习记录

​ 此篇为第一章,比较基础,适合想入门spring源码的,并且已经学习使用过spring框架的同学朋友观看,后续篇章还在学习更新中

​ 如有错误,务必私信我或在评论区指出,我会立即更新,十分感谢

PS:

​ 如果要问为什么学习spring源码,我会老实告诉你:我的首要目的就是面试

​ 而老师说,学习spring源码,是因为spring是基础,后续的springmvc,springboot,springcloud都是在spring基础之上进行扩展衍生。spring作为最基础的框架具有十分优秀的扩展性,学习了spring源码我们就能知道spring是怎样构建的,并且怎样去扩展spring,如使用自定义BeanPostProcessor对我们的bean进行增强。(当然如果你说我百度一下就学会了,那也是牛的,百度程序员CV大法天下无敌)

​ 总而言之,老师的目的就是通过对Spring源码的学习,让我们对Spring为所欲为!!!(咳咳,为什么我会想到爱情公寓里的成语接龙,为所欲为下一个)

​ 废话不多说,开始学习!

Spring概述

一、简单构想Spring容器

  1. 想要学习搞懂Spring必须要清楚IOC和AOP,Spring就是一个IOC容器,里面装的是bean。当我们执行getBean操作时就可以获取到bean进行使用。

构想spring容器

  1. 如果让我们去想一下spring容器在获取bean时需要经过哪些步骤,如上图可以分析出:

     ​加载xml ——> 解析xml ——> 封装BeanDefinition(bean定义信息)——> 实例化 ——> 放到容器中 ——> 从容器中获取(这里会涉及到三级缓存)
    
  2. Spring作为一个容器,我们可以想到很多存取的办法,如list,set等等,Spring用的是Map结构存储bean。如上我们使用getBean时要传入的参数,就是装着bean的map其中的key,通过这个key我们可以取到Object,ObjectFactory,BeanDefinition等对象信息。

二、深入探究Spring容器

bean的加载流程

1、xml转beanDefinition
  1. bean的定义信息有很多种方式,最常用的xml形式,还有properties,yaml,json等文件都可以定义bean的信息,对应着我们就需要一个BeanDefinitionReader类来帮助我们读取配置文件,提取出对应的beanDefinition。

    ​ 打开BeanDefinition的Structure我们可以看到beanDefinition内有很多对应的获取bean信息的方法

在这里插入图片描述

2.beanDefinition到实例化需要干什么
  1. 有了beanDefinition,我们其实已经可以通过反射去实例化一个bean了(为什么不用new的问题我建议去百度,我认为最大的原因反射可以解耦),但是Spring没有这样做,中间有一个BeanFactory的重要角色。BeanFactory也叫bean工厂,是整个容器的根接口,也是容器的入口

  2. BeanFactory有个很重要子类DefaultListableBeanFactory,以下是它的类图,讲课老师希望我们眼熟它!

    在这里插入图片描述

  3. 回到刚才的问题,为什么我们需要BeanFactory,从beanDefinition到实例化我们可能会遇到在容器创建过程中需要动态的改变bean的信息怎么办?

​ 例如

<property name=url value=${jdbc.url}>

​ 这段代码咋们都熟悉吧,其中 ${jdbc.url} 是要转换成配置文件中写好的值的,这其中是怎么转换的,并且我们想随时的修改beanDefinition应该怎么办呢?

  1. 此时我们的PostProcessor闪亮登场,PostProcessor也叫后置处理器,增强器,分为BeanFactoryPostProcessorBeanPostProcessor

     BeanFactoryPostProcessor:增强beanDefinition信息
     
     BeanPostProcessor:增强bean信息
    

在这里插入图片描述

​ 举个例子,我们来看看这个类PlaceholderConfigurerSupport

在这里插入图片描述

​ 上图的默认前缀 ”${ ” 和后缀 ”}” 大家看看是不是很眼熟,PlaceholderConfigurerSupport的父类PropertyResourceConfigurer就继承了BeanFactoryPostProcessor接口。

​ 对BeanFactoryPostProcessor感兴趣或者疑惑的朋友可以自己写一个类去实现BeanFactoryPostProcessor接口,重写里面的方法就可以对beanDefinition进行任意的修改操作了,如下图所示

在这里插入图片描述

  1. 所以我们的beanDefinition在实例化前,会经过多个BeanFactoryPostProcessor进行增强,也就是所谓的拓展操作,最终走到实例化的步骤
3. bean实例化(bean的生命周期)
  1. bean的实例化在spring中也是个很重要的内容,首先我们要确定的是,实例化其实就是创建对象,我们之前都是new使用构造器直接将开辟对象内存空间,属性啊,初始化方法全给我们处理完了。

​ 但是在spring中我们将创建对象分为实例化和初始化。

		实例化:在堆中开辟了一块空间用来存放对象,此时对象的属性值都是默认值
		
		初始化:给属性设置值,填充属性和执行初始化方法(init-method)

在这里插入图片描述

  1. 让我们再仔细看看下面这张图

在这里插入图片描述

当我们实例化好bean也就是分配好了内存空间,spring在bean的初始化上下了很大功夫

​ 从

填充属性(populate) ——> 设置Aware接口的属性 ——> BeanPostProcessor:before ——> 执行init-method方法——> 	BeanPostProcessor:after

最终我们获取到了完整对象

  1. 相信很多同学都和我一样有个疑问,Aware是什么?

Aware是一个接口,中文意思是 意识 ,官方对Aware的解释是:一个标记超接口,指示bean有资格通过回调样式方法被Spring容器通知特定框架对象。实际的方法签名由各个子接口确定,但通常只应由一个接受单个参数的返回空值的方法组成

​ 其实我也没看懂哈哈,接下来举例给大家应该就清楚了:

当我们用getBean获取到对象时,如果我们想获取bean的当前容器怎么办?如下图

在这里插入图片描述

此时Aware就发挥作用了,到bean也就是A类下实现ApplicationContextAware接口(EnvironmentAware是用来获取环境对象的)

在这里插入图片描述

重写setApplicationContext方法

在这里插入图片描述

​ 这样我们就可以从bean中获取到对应的当前容器对象了
在这里插入图片描述

同理EnvironmentAware接口也可以获取到环境对象。

总结:Aware有七百多个实现类,当Spring容器创建的bean对象在进行具体操作的时候,如果需要容器的其他对象,此时可以将对象实现Aware接口,来满足当前的需要。(bean实现Aware接口可以实现获取容器对象,环境对象及其他各种功能,算是对bean的功能扩展。)

  1. 执行初始化方法init-method前后都有BeanPostProcessor的前置增强和后置增强方法。我们可以看BeanPostProcessor的源码:
public interface BeanPostProcessor {
    
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
    
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

对比BeanFactoryPostProcessor:

@FunctionalInterface
public interface BeanFactoryPostProcessor {

	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

BeanPostProcessor会在初始化方法init-method的前后对bean都做了增强的处理

典型的例子就是aop,Spring使用BeanPostProcessor:after实现了对bean的代理,具体实现类看AbstractAutoProxyCreator,里面postProcessAfterInitialization方法的wrapIfNecessary,感兴趣的同学可以追进去看看

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
		implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
/**
	 * Create a proxy with the configured interceptors if the bean is
	 * identified as one to proxy by the subclass.
	 * 如果子类将bean标识为代理,则使用配置的拦截器创建代理。
	 * @see #getAdvicesAndAdvisorsForBean
	 */
	@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}
}
  1. 经过上述这些步骤我们就获得了完整的bean对象,这也是bean的生命周期(还差bean的销毁过程)
4.一些对spring容器的补充说明
  1. 以上是spring容器对bean的创建,但是我们应该想到,在我们创建bean的时候,像一些最基本的如BeanFactory,以及里面用到的最基础的如PostProcessor,这些类是不是应该提前创建以便我们使用

    这就涉及到bean的分类

    SpringBean分为普通对象和容器对象

        普通对象:我们自定义需要的对象(即xml里自己写的bean)
     
        容器对象:内置对象Spring需要的对象
    

在这里插入图片描述

  1. 为什么初始化的顺序是这样的?

    初始化顺序是Spring定义的,在BeanFactory中我们可以找到这样的注释

    /** <p>Bean factory implementations should support the standard bean lifecycle interfaces
     * as far as possible. The full set of initialization methods and their standard order is:
     * Bean工厂实现应尽可能支持标准Bean生命周期接口。整套初始化方法及其标准顺序为:
     * <ol>
     * <li>BeanNameAware's {@code setBeanName}
     * <li>BeanClassLoaderAware's {@code setBeanClassLoader}
     * <li>BeanFactoryAware's {@code setBeanFactory}
     * <li>EnvironmentAware's {@code setEnvironment}
     * <li>EmbeddedValueResolverAware's {@code setEmbeddedValueResolver}
     * <li>ResourceLoaderAware's {@code setResourceLoader}
     * (only applicable when running in an application context)
     * <li>ApplicationEventPublisherAware's {@code setApplicationEventPublisher}
     * (only applicable when running in an application context)
     * <li>MessageSourceAware's {@code setMessageSource}
     * (only applicable when running in an application context)
     * <li>ApplicationContextAware's {@code setApplicationContext}
     * (only applicable when running in an application context)
     * <li>ServletContextAware's {@code setServletContext}
     * (only applicable when running in a web application context)
     * <li>{@code postProcessBeforeInitialization} methods of BeanPostProcessors
     * <li>InitializingBean's {@code afterPropertiesSet}
     * <li>a custom {@code init-method} definition
     * <li>{@code postProcessAfterInitialization} methods of BeanPostProcessors
     * </ol>
     *
     * <p>On shutdown of a bean factory, the following lifecycle methods apply:
     * 在关闭bean工厂时,以下生命周期方法适用:
     * <ol>
     * <li>{@code postProcessBeforeDestruction} methods of DestructionAwareBeanPostProcessors
     * <li>DisposableBean's {@code destroy}
     * <li>a custom {@code destroy-method} definition
     * </ol>
     **/
    
    1. 那么这个顺序是如何维持的呢?(在不同的阶段要处理不同的工作,应该怎么办)

        Spring采用了观察者模式的设计模式来解决这个问题,使用监听器,监听时间,多播器(也叫广播器)
      

    ​ 在refresh()方法里我们可以看到事件监听器和事件注册的方法,(refresh()方法是Spring容器创建和刷新用到的很重要· 的方法,里面包含13个小方法完成Spring容器的创建刷新,后面会讲到)

三、Spring创建的具体流程

1. new ClassPathXmlApplicationContext(“XXX.xml”)发生了什么

在这里插入图片描述

  1. 上图就是我们日常使用Spring时new出一个ApplicationContext后,就可以用它getBean获取我们需要的bean进行开发

让我们进入ClassPathXmlApplicationContext一探究竟

  1. 当我们进去时可以发现有三个方法

    • super(parent):父类的构造方法,调用父类构造方法会在里面进行相关的对象创建等操作,包含属性的赋值操作,这些属性在后续的refresh()方法中我们会看到
    • setConfigLocations(configLocations):进行资源文件路径的设置,就是我们传入的applicationContext.xml
    • refresh():内含13个方法,是Spring的核心步骤,掌握这13个方法,就可以说你懂Spring源码了

在这里插入图片描述

2.refresh方法

​ 13种方法

  1. prepareRefresh();

    • 做容器刷新前的准备工作

      - 设置容器的启动时间
      
      - 设置活跃状态为true
      
      - 设置关闭状态为false
      
      - 获取Environment对象,并加载当前系统的属性值到Environment对象中
      
      - 准备监听器和时间的集合对象,默认为空的集合
      
  2. obtainFreshBeanFactory();

    - 创建容器对象:DefaultListableBeanFactory
    
    - 加载xml配置文件的属性值到当前工厂中,最重要的就是BeanDefinition
    
  3. prepareBeanFactory(beanFactory);

    - 完善BeanFactory
    
    - 初始化beanExpressionResolvr(解析Expression表达式的#{})
    
      - propertyEditorRegisters类型转换器
    
      - resolvableDependencies管理特殊对象进行依赖注入如:BeanFactory
    
      - BeanPostProcessor 加入了两个内置的Bean处理器(作用不大)在bean创建时对bean各项功能进行扩展,注解识别
    
  4. postProcessBeanFactory(beanFactory);

    - 空实现,留给子类扩展
    
  5. invokeBeanFactoryPostProcessors(beanFactory);

    - 调用BeanFactory的后处理器,对BeanFactory进行扩展
    
      - 如ConfigurationClassPostProcessor,可以解析@Configuration,@Bean,@Import,@PropertySource
    
    ​	
    
  6. registerBeanPostProcessors(beanFactory);

    - 添加Bean的后处理器,去beanDefinitionMap中寻找实现了BeanPostProcessor接口的特殊Bean
    
    - 有就把它创建出来加入beanPostProcessor集合中去
    
      		 * 	常见的BeanPostProcessor
      	
      	 * AutowiredAnnotationBeanPostProcessor 解析@Autowire,@Value
      	
      	 * CommonAnnotationBeanPostProcessor 解析@Resource,@PostConstruction,@PreDestory
      	
      	 * AnnotationAwareAspectJAutoProxyCreator 解析@Aspect 为符合切点目标Bean自动代理
    
  7. initMessageSource();

    - 给MessageSource变量赋值,实现国际化功能
    
  8. initApplicationEventMulticaster();

    - 初始化applicationEventMulticaster,应用程序时间的广播器,发送事件
    
    - initMessageSource(); 和initApplicationEventMulticaster(); 两个方法都从BeanDefinitionMap中找实现了对应接口的Bean,没有就空实现或者默认实现
    
  9. onRefresh();

    - 空实现,留给子类扩展,如SpringBoot中的子类可以在这里准备WebServer即内嵌web容器
    
  10. registerListeners();

    - 注册监听器到applicationEventMulticaster的defaultRetriever集合中
      * 监听器来自编程,容器,bean,或@EventListener的解析
    
  11. finishBeanFactoryInitialization(beanFactory);

    - 补充BeanFactory剩下的三个成员,并且会在这一步查找所有非延迟单例对象,创建并添加到单例池
       * conversionService:也是转换机制,作为对PropertyEditor的补充
    
       * embeddedValueResolvers:内嵌值解析器,用来解析@Value中的${},实际是借用Environment实现
    
       * singletonObject:单例池,用来保存所有的单例对象
    
  12. finishRefresh();

    - 创建lifecycleProcessor生命周期处理器,用来控制容器内需要生命周期管理的Bean
    
    - 调用context的start或stop,即可出发所有实现lifecycle接口bean的start或stop方法
    
    - 发布contextRefreshed事件
    
  13. resetCommonCaches();

    - 这个方法始终会被执行,它的作用就是清理各种缓存以及classLoader
         * ReflectionUtils:清理的是和反射相关的缓存
    
         * AnnotationUtils:清理的是和注解相关的缓存
    
         * ResolvableType:清理的是和解析类型相关的缓存
    
         * CachedIntrospectionResults.clearClassLoader:清理的是类加载器的相关缓存
    
@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

			// 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
			 **/
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			/**
			 *  完善BeanFactory
			 * 	初始化beanExpressionResolvr(解析Expression表达式的#{})
			 * 	propertyEditorRegisters类型转换器
			 * 	resolvableDependencies管理特殊对象进行依赖注入如:BeanFactory
			 * 	BeanPostProcessor 加入了两个内置的Bean处理器(作用不大)在bean创建时对bean各项功能进行扩展,注解识别
			 **/
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				/**
				 *  空实现,留给子类扩展
				 *
				 **/
				postProcessBeanFactory(beanFactory);

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// Invoke factory processors registered as beans in the context.
				/**
				 *  调用BeanFactory的后处理器,对BeanFactory进行扩展
				 * 	如ConfigurationClassPostProcessor,可以解析@Configuration,@Bean,@Import,@PropertySource
				 **/
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				/**
				 *  添加Bean的后处理器,去beanDefinitionMap中寻找实现了BeanPostProcessor接口的特殊Bean
				 * 	有就把它创建出来加入beanPostProcessor集合中去
				 * 	常见的BeanPostProcessor
				 * 	AutowiredAnnotationBeanPostProcessor 解析@Autowire,@Value
				 * 	CommonAnnotationBeanPostProcessor 解析@Resource,@PostConstruction,@PreDestory
				 * 	AnnotationAwareAspectJAutoProxyCreator 解析@Aspect 为符合切点目标Bean自动代理
				 **/
				registerBeanPostProcessors(beanFactory);
				beanPostProcess.end();

				// Initialize message source for this context.
				/**
				 *  给MessageSource变量赋值,实现国际化功能
				 **/
				initMessageSource();

				// Initialize event multicaster for this context.
				/**
				 *  初始化applicationEventMulticaster,应用程序时间的广播器,发送事件
				 *
				 *
				 *  initMessageSource();和initApplicationEventMulticaster();两个方法都从BeanDefinitionMap中找实现了对应接口的Bean,没有就空实现或者默认实现
				 **/
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				/**
				 *  空实现,留给子类扩展,如SpringBoot中的子类可以在这里准备WebServer即内嵌web容器
				 **/
				onRefresh();

				// Check for listener beans and register them.
				/**
				 *  注册监听器到applicationEventMulticaster的defaultRetriever集合中
				 *  监听器来自编程,容器,bean,或@EventListener的解析
				 **/
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				/**
				 *  补充BeanFactory剩下的三个成员,并且会在这一步查找所有非延迟单例对象,创建并添加到单例池
				 *  conversionService:也是转换机制,作为对PropertyEditor的补充
				 *  embeddedValueResolvers:内嵌值解析器,用来解析@Value中的${},实际是借用Environment实现
				 *  singletonObject:单例池,用来保存所有的单例对象
				 **/
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				/**
				 *  创建lifecycleProcessor生命周期处理器,用来控制容器内需要生命周期管理的Bean
				 * 	调用context的start或stop,即可出发所有实现lifecycle接口bean的start或stop方法
				 * 	发布contextRefreshed事件
				 **/
				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.
				destroyBeans();

				// Reset 'active' flag.
				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...
                /**
				 * 	这个方法始终会被执行,它的作用就是清理各种缓存以及classLoader
				 * 	ReflectionUtils:清理的是和反射相关的缓存
				 * 	AnnotationUtils:清理的是和注解相关的缓存
				 * 	ResolvableType:清理的是和解析类型相关的缓存
				 * 	CachedIntrospectionResults.clearClassLoader:清理的是类加载器的相关缓存
				 **/
				resetCommonCaches();
				contextRefresh.end();
			}
		}
	}

四、鸟瞰图

在这里插入图片描述

后话

看到这的朋友希望能给我来个一键三连,万分感谢

后续的学习就是围绕这13个方法一步步深入去了解spring源码,剖析里面进行了怎样的流程

我也会继续更新后续的笔记,时间不定

如果有同学朋友想跟我一起学习马某人的spring源码教学,可以私信联系我,因为我的资料也是购买的而且很贵,里面包含了spring,springmvc,springboot,mybatis,都是源码层面的教学视频。

所以你只要拿着一键三连的截图,并付出一点点的money,我就会将我的资料给你,不便宜你打我!!!(笔记的md版不用钱,图片资料也不用,就视频是我买来的,真的很便宜感兴趣可以私信问我)

好啦,下次见,谢谢您的观看,祝您天天开心

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值