Spring源码分析(一)
前言
? 本人在研究生时期的项目一直是使用的C++,到毕设时导师给定的课题需要用Java实现,所以当时简单的学了SSM框架。当时也仅限于知道Spring的简单的使用,找工作用的也是C/C++,可是入职后三个月为了适应公司的需求,“自愿”转了java,由于有研究生时候的经验,所以相比于其他转java的同事,我情况可能还是比较好的。
? 转java后也用的都是公司现成的框架,项目都是现成的,骨架都早已搭好,只需会基本的if-else,再加上照着之前的代码框架写就行了,一直也没时间(其实就是沉醉在刚入职的新鲜感中,没有想着去看,疏忽了个人的成长)去好好看看Spring,spring的水平也一直停留在毕设时简单使用的水平,也没有对Spring有太多重视。到现在两年了,考虑换公司,发现我一个搞java 的连Spring的源码都没看过,有点说不过去,于是开始找资料了解Spring源码(所以跳槽让人技术成长)。
? 本人看的是从同事那里分享的《子路》讲的源码系列,本博客的目的有三个:
- 通过写博客,巩固自己看视频所得。
- 做记录,以便自己之后翻看,回顾。
- 可以发表出来让网友进行观看,以便于发现自己写的是否有问题。
好了,废话不多说,开始吧。
准备工作
IDE运行spring源码。(我的是5.0.x)
Spring环境初始化流程(一)
Spring环境的初始化,在没有SpringMVC的情况下,通过在main方法中创建ApplicationContext 来初始化Spring环境。鉴于springboot的兴起,注解方式逐渐取代了XML的方式(其实就是人家子路讲的就是这个·······),所以使用 AnnotationConfigApplicationContext 来初始化spring环境。
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
通过上述代码就创建好了一个spring环境,接下里就可以使用applicationContext调用getBean方法获取bean实例了。通过点进去上面一行代码可以看到它主要做了四个动作:
this();
register(annotatedClasses);
refresh();
明明只有三个语句,为什么是四个动作?因为在调用this()无参构造方法时肯定会先构造父类,所以还隐含着有一个父类的构造方法。
1. 父类构造方法
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
可以看到,在父类构造方法中,就干了一件事:进行beanFactory的初始化。(当然了,在DefaultListableBeanFactory 的构造方法中也进行了一些设置,这这些我们前期可以忽略,不会对主流程产生影响)
BeanFactory:构建Bean的工厂,spring环境中最重要的组件,它里面包含了生成bean所需要的原料(BeanDefinitionMap)和工具(比如各种后置处理器),以及存放bean实例的容器(singletonObjects)。
BeanDefinitionMap:bean工厂重要容器,存放<beanNAME, beanDefinition>对。(下文简称BDMap)
Beandefinition:Bean的定义,一个BeanDefinition描述了一个bean的各种属性,比如是否单例、是否懒加载,它的class,根据bd来生成bean实例
2. this(), 即AnnotationConfigApplicationContext()
在AnnotationConfigApplicationContext 的无参构造方法中,完成了两件事儿,初始化两个组件:reader和scanner,其中第一件很重要。
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
1) AnnotatedBeanDefinitionReader
通过点进构造方法进一步跟踪代码,很容易定位到以下代码:
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source){
}
这个方法可以看到分别判断BDMap中是否含有以下七个name的BD
org.springframework.context.annotation.internalConfigurationAnnotationProcessor->ConfigurationClassPostProcessor.class
org.springframework.context.annotation.internalAutowiredAnnotationProcessor->AutowiredAnnotationBeanPostProcessor.class
org.springframework.context.annotation.internalRequiredAnnotationProcessor->RequiredAnnotationBeanPostProcessor.class
org.springframework.context.annotation.internalCommonAnnotationProcessor->CommonAnnotationBeanPostProcessor.class
# org.springframework.context.annotation.internalPersistenceAnnotationProcessor->PersistenceAnnotationBeanPostProcessor.class
org.springframework.context.event.internalEventListenerProcessor->EventListenerMethodProcessor.class
org.springframework.context.event.internalEventListenerFactory->DefaultEventListenerFactory.class
如果不包含(这里是初始化,肯定不包含),则将以上七个name对应的class生成BD,然后调用以下方法:
private static BeanDefinitionHolder registerPostProcessor(
BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName){}
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition){
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
registerBeanDefinition 方法完成beanDefinition的注册,即将以上六个BD放入BeanFactory中的BDMap中,(PersistenceAnnotationBeanPostProcessor 比较特殊不做讨论).
这里可以看到:
-
把A类转换成BD的方法:XXXBeanDefinition bd = new XXXbeanDefinition(A.class); XXXBeanDefinition表示Spring内部有多种BeanDefinition类型,这里用的是RootBeanDefinition,表示是spring内部的,还有AnnotatedBeandefinition等 -
AnnotatedBeanDefinitionReader 的作用:BD读取器。
本步骤完成了spring内部六个BD 的注册;
2) ClassPathBeanDefinitionScanner
“可以” 用来扫描包或者类,继而转成BD; 但是实际上环境初始化扫描包的工作不是scanner对象来完成的; 而是在refresh时调用的invokeBeanFactoryPostProcessors方法中new了一个ClassPathBeanDefinitionScaaner来完成包扫描的; 这里的scanner仅仅是为了程序员能够在外部调用AnnotationApplicationContext中的scan方法;
也就是说在spring自动初始化过程中用不到这个scanner
3. register(annotatedClasses)
这里的annotatedClasses一般都会是一个配置类(即带@Configuration和@ComponentScan注解的类)。
这个方法完成的事情是:将配置类注册到BDMap中,第一个用户类,Spring无法自动获取,需要用户手动注册,之后的其他类则可以通过ComponentScan实现自动扫描。
总结
以上三步大致总结如下:
- 初始化默认BeanFactory
- 注册六个spring内部的BD(这几个BD都是spring内部的后置处理器,属于spring的扩展点,用户自己也可以参照这几个类开发自己的类,介入spring的流程)
- 注册用户配置类
以上三步完成了初始化spring环境进行初始化的准备工作。第四步refresh() 是重头戏!会完成工厂的初始化和bean的实例化。
|