Spring源码分析(一)

Spring源码分析(一)

前言

​ 本人在研究生时期的项目一直是使用的C++,到毕设时导师给定的课题需要用Java实现,所以当时简单的学了SSM框架。当时也仅限于知道Spring的简单的使用,找工作用的也是C/C++,可是入职后三个月为了适应公司的需求,“自愿”转了java,由于有研究生时候的经验,所以相比于其他转java的同事,我情况可能还是比较好的。

​ 转java后也用的都是公司现成的框架,项目都是现成的,骨架都早已搭好,只需会基本的if-else,再加上照着之前的代码框架写就行了,一直也没时间(其实就是沉醉在刚入职的新鲜感中,没有想着去看,疏忽了个人的成长)去好好看看Spring,spring的水平也一直停留在毕设时简单使用的水平,也没有对Spring有太多重视。到现在两年了,考虑换公司,发现我一个搞java 的连Spring的源码都没看过,有点说不过去,于是开始找资料了解Spring源码(所以跳槽让人技术成长)。

​ 本人看的是从同事那里分享的《子路》讲的源码系列,本博客的目的有三个:

  1. 通过写博客,巩固自己看视频所得。
  2. 做记录,以便自己之后翻看,回顾。
  3. 可以发表出来让网友进行观看,以便于发现自己写的是否有问题。

好了,废话不多说,开始吧。

准备工作

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. 父类构造方法
// GenericApplicationContext.java

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,其中第一件很重要。

//AnnotationConfigApplicationContext.java

// 可以看到参数传的是this,即整个环境上下文,而参数类型要求是registry,通过查看代码,发现果然GenericApplicationContext实现了BeanDefinitionRegistry接口
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
1) AnnotatedBeanDefinitionReader

通过点进构造方法进一步跟踪代码,很容易定位到以下代码:

// AnnotationConfigUtils.java
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,然后调用以下方法:

// AnnotationConfigUtils.java
private static BeanDefinitionHolder registerPostProcessor(
			BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName){}
// DefaultListableBeanFactory.java
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比较特殊不做讨论).

这里可以看到:

  1. 把A类转换成BD的方法:XXXBeanDefinition bd = new XXXbeanDefinition(A.class);

    XXXBeanDefinition表示Spring内部有多种BeanDefinition类型,这里用的是RootBeanDefinition,表示是spring内部的,还有AnnotatedBeandefinition等

  2. 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实现自动扫描。

总结

以上三步大致总结如下:

  1. 初始化默认BeanFactory
  2. 注册六个spring内部的BD(这几个BD都是spring内部的后置处理器,属于spring的扩展点,用户自己也可以参照这几个类开发自己的类,介入spring的流程)
  3. 注册用户配置类

以上三步完成了初始化spring环境进行初始化的准备工作。第四步refresh() 是重头戏!会完成工厂的初始化和bean的实例化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值