Spring源码学习
前言
此学习笔记是我个人通过马某人的教学视频进行学习记录
此篇为第一章,比较基础,适合想入门spring源码的,并且已经学习使用过spring框架的同学朋友观看,后续篇章还在学习更新中
如有错误,务必私信我或在评论区指出,我会立即更新,十分感谢
PS:
如果要问为什么学习spring源码,我会老实告诉你:我的首要目的就是面试
而老师说,学习spring源码,是因为spring是基础,后续的springmvc,springboot,springcloud都是在spring基础之上进行扩展衍生。spring作为最基础的框架具有十分优秀的扩展性,学习了spring源码我们就能知道spring是怎样构建的,并且怎样去扩展spring,如使用自定义BeanPostProcessor对我们的bean进行增强。(当然如果你说我百度一下就学会了,那也是牛的,百度程序员CV大法天下无敌)
总而言之,老师的目的就是通过对Spring源码的学习,让我们对Spring为所欲为!!!(咳咳,为什么我会想到爱情公寓里的成语接龙,为所欲为下一个)
废话不多说,开始学习!
Spring概述
一、简单构想Spring容器
- 想要学习搞懂Spring必须要清楚IOC和AOP,Spring就是一个IOC容器,里面装的是bean。当我们执行getBean操作时就可以获取到bean进行使用。
-
如果让我们去想一下spring容器在获取bean时需要经过哪些步骤,如上图可以分析出:
加载xml ——> 解析xml ——> 封装BeanDefinition(bean定义信息)——> 实例化 ——> 放到容器中 ——> 从容器中获取(这里会涉及到三级缓存)
-
Spring作为一个容器,我们可以想到很多存取的办法,如list,set等等,Spring用的是Map结构存储bean。如上我们使用getBean时要传入的参数,就是装着bean的map其中的key,通过这个key我们可以取到Object,ObjectFactory,BeanDefinition等对象信息。
二、深入探究Spring容器
1、xml转beanDefinition
-
bean的定义信息有很多种方式,最常用的xml形式,还有properties,yaml,json等文件都可以定义bean的信息,对应着我们就需要一个BeanDefinitionReader类来帮助我们读取配置文件,提取出对应的beanDefinition。
打开BeanDefinition的Structure我们可以看到beanDefinition内有很多对应的获取bean信息的方法
2.beanDefinition到实例化需要干什么
-
有了beanDefinition,我们其实已经可以通过反射去实例化一个bean了(为什么不用new的问题我建议去百度,我认为最大的原因反射可以解耦),但是Spring没有这样做,中间有一个BeanFactory的重要角色。BeanFactory也叫bean工厂,是整个容器的根接口,也是容器的入口。
-
BeanFactory有个很重要子类DefaultListableBeanFactory,以下是它的类图,讲课老师希望我们眼熟它!
-
回到刚才的问题,为什么我们需要BeanFactory,从beanDefinition到实例化我们可能会遇到在容器创建过程中需要动态的改变bean的信息怎么办?
例如
<property name=url value=${jdbc.url}>
这段代码咋们都熟悉吧,其中 ${jdbc.url} 是要转换成配置文件中写好的值的,这其中是怎么转换的,并且我们想随时的修改beanDefinition应该怎么办呢?
-
此时我们的PostProcessor闪亮登场,PostProcessor也叫后置处理器,增强器,分为BeanFactoryPostProcessor和BeanPostProcessor
BeanFactoryPostProcessor:增强beanDefinition信息 BeanPostProcessor:增强bean信息
举个例子,我们来看看这个类PlaceholderConfigurerSupport
上图的默认前缀 ”${ ” 和后缀 ”}” 大家看看是不是很眼熟,PlaceholderConfigurerSupport的父类PropertyResourceConfigurer就继承了BeanFactoryPostProcessor接口。
对BeanFactoryPostProcessor感兴趣或者疑惑的朋友可以自己写一个类去实现BeanFactoryPostProcessor接口,重写里面的方法就可以对beanDefinition进行任意的修改操作了,如下图所示
- 所以我们的beanDefinition在实例化前,会经过多个BeanFactoryPostProcessor进行增强,也就是所谓的拓展操作,最终走到实例化的步骤
3. bean实例化(bean的生命周期)
- bean的实例化在spring中也是个很重要的内容,首先我们要确定的是,实例化其实就是创建对象,我们之前都是new使用构造器直接将开辟对象内存空间,属性啊,初始化方法全给我们处理完了。
但是在spring中我们将创建对象分为实例化和初始化。
实例化:在堆中开辟了一块空间用来存放对象,此时对象的属性值都是默认值
初始化:给属性设置值,填充属性和执行初始化方法(init-method)
- 让我们再仔细看看下面这张图
当我们实例化好bean也就是分配好了内存空间,spring在bean的初始化上下了很大功夫
从
填充属性(populate) ——> 设置Aware接口的属性 ——> BeanPostProcessor:before ——> 执行init-method方法——> BeanPostProcessor:after
最终我们获取到了完整对象
- 相信很多同学都和我一样有个疑问,Aware是什么?
Aware是一个接口,中文意思是 意识 ,官方对Aware的解释是:一个标记超接口,指示bean有资格通过回调样式方法被Spring容器通知特定框架对象。实际的方法签名由各个子接口确定,但通常只应由一个接受单个参数的返回空值的方法组成。
其实我也没看懂哈哈,接下来举例给大家应该就清楚了:
当我们用getBean获取到对象时,如果我们想获取bean的当前容器怎么办?如下图
此时Aware就发挥作用了,到bean也就是A类下实现ApplicationContextAware接口(EnvironmentAware是用来获取环境对象的)
重写setApplicationContext方法
这样我们就可以从bean中获取到对应的当前容器对象了
同理EnvironmentAware接口也可以获取到环境对象。
总结:Aware有七百多个实现类,当Spring容器创建的bean对象在进行具体操作的时候,如果需要容器的其他对象,此时可以将对象实现Aware接口,来满足当前的需要。(bean实现Aware接口可以实现获取容器对象,环境对象及其他各种功能,算是对bean的功能扩展。)
- 在执行初始化方法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;
}
}
- 经过上述这些步骤我们就获得了完整的bean对象,这也是bean的生命周期(还差bean的销毁过程)
4.一些对spring容器的补充说明
-
以上是spring容器对bean的创建,但是我们应该想到,在我们创建bean的时候,像一些最基本的如BeanFactory,以及里面用到的最基础的如PostProcessor,这些类是不是应该提前创建以便我们使用
这就涉及到bean的分类
SpringBean分为普通对象和容器对象
普通对象:我们自定义需要的对象(即xml里自己写的bean) 容器对象:内置对象Spring需要的对象
-
为什么初始化的顺序是这样的?
初始化顺序是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> **/
-
那么这个顺序是如何维持的呢?(在不同的阶段要处理不同的工作,应该怎么办)
Spring采用了观察者模式的设计模式来解决这个问题,使用监听器,监听时间,多播器(也叫广播器)
在refresh()方法里我们可以看到事件监听器和事件注册的方法,(refresh()方法是Spring容器创建和刷新用到的很重要· 的方法,里面包含13个小方法完成Spring容器的创建刷新,后面会讲到)
-
三、Spring创建的具体流程
1. new ClassPathXmlApplicationContext(“XXX.xml”)发生了什么
- 上图就是我们日常使用Spring时new出一个ApplicationContext后,就可以用它getBean获取我们需要的bean进行开发
让我们进入ClassPathXmlApplicationContext一探究竟
-
当我们进去时可以发现有三个方法
- super(parent):父类的构造方法,调用父类构造方法会在里面进行相关的对象创建等操作,包含属性的赋值操作,这些属性在后续的refresh()方法中我们会看到
- setConfigLocations(configLocations):进行资源文件路径的设置,就是我们传入的applicationContext.xml
- refresh():内含13个方法,是Spring的核心步骤,掌握这13个方法,就可以说你懂Spring源码了
2.refresh方法
13种方法
-
prepareRefresh();
-
做容器刷新前的准备工作
- 设置容器的启动时间 - 设置活跃状态为true - 设置关闭状态为false - 获取Environment对象,并加载当前系统的属性值到Environment对象中 - 准备监听器和时间的集合对象,默认为空的集合
-
-
obtainFreshBeanFactory();
- 创建容器对象:DefaultListableBeanFactory - 加载xml配置文件的属性值到当前工厂中,最重要的就是BeanDefinition
-
prepareBeanFactory(beanFactory);
- 完善BeanFactory - 初始化beanExpressionResolvr(解析Expression表达式的#{}) - propertyEditorRegisters类型转换器 - resolvableDependencies管理特殊对象进行依赖注入如:BeanFactory - BeanPostProcessor 加入了两个内置的Bean处理器(作用不大)在bean创建时对bean各项功能进行扩展,注解识别
-
postProcessBeanFactory(beanFactory);
- 空实现,留给子类扩展
-
invokeBeanFactoryPostProcessors(beanFactory);
- 调用BeanFactory的后处理器,对BeanFactory进行扩展 - 如ConfigurationClassPostProcessor,可以解析@Configuration,@Bean,@Import,@PropertySource
-
registerBeanPostProcessors(beanFactory);
- 添加Bean的后处理器,去beanDefinitionMap中寻找实现了BeanPostProcessor接口的特殊Bean - 有就把它创建出来加入beanPostProcessor集合中去 * 常见的BeanPostProcessor * AutowiredAnnotationBeanPostProcessor 解析@Autowire,@Value * CommonAnnotationBeanPostProcessor 解析@Resource,@PostConstruction,@PreDestory * AnnotationAwareAspectJAutoProxyCreator 解析@Aspect 为符合切点目标Bean自动代理
-
initMessageSource();
- 给MessageSource变量赋值,实现国际化功能
-
initApplicationEventMulticaster();
- 初始化applicationEventMulticaster,应用程序时间的广播器,发送事件 - initMessageSource(); 和initApplicationEventMulticaster(); 两个方法都从BeanDefinitionMap中找实现了对应接口的Bean,没有就空实现或者默认实现
-
onRefresh();
- 空实现,留给子类扩展,如SpringBoot中的子类可以在这里准备WebServer即内嵌web容器
-
registerListeners();
- 注册监听器到applicationEventMulticaster的defaultRetriever集合中 * 监听器来自编程,容器,bean,或@EventListener的解析
-
finishBeanFactoryInitialization(beanFactory);
- 补充BeanFactory剩下的三个成员,并且会在这一步查找所有非延迟单例对象,创建并添加到单例池 * conversionService:也是转换机制,作为对PropertyEditor的补充 * embeddedValueResolvers:内嵌值解析器,用来解析@Value中的${},实际是借用Environment实现 * singletonObject:单例池,用来保存所有的单例对象
-
finishRefresh();
- 创建lifecycleProcessor生命周期处理器,用来控制容器内需要生命周期管理的Bean - 调用context的start或stop,即可出发所有实现lifecycle接口bean的start或stop方法 - 发布contextRefreshed事件
-
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版不用钱,图片资料也不用,就视频是我买来的,真的很便宜感兴趣可以私信问我)
好啦,下次见,谢谢您的观看,祝您天天开心