一. 学习源码的目的

  1. 为了扩展和调优:掌握框架的工作流程和原理

  2. 为了提升自己的编程技能:学习他人的设计思想、编程技巧

二. 学习源码的方法

方法一:

  1)掌握研究的对象和研究对象的核心概念:搞明白框架都能做什么,是怎么做的。

    比如我们要研究Spring的源码,那么研究的对象就是Spring,Spring的核心概念有IOC、DI、AOP等,那么我们就需要搞明白这些核心概念能做什么,是怎么做的

  2)从整体到部分

    首先要弄清楚整体是由哪些部分组成起来工作的,然后再去研究各个部分是怎么做的。比如我们现在研究Spring IOC,就要先弄清楚IOC由创建bean定义、注册bean定义、bean工厂几部分组合起来工作的,然后再去研究这几个部分是怎么做的

  3)找到入口,先理清楚主干流程,然后再去研究各个流程的细节

    比如我们要研究Spring是怎么加载xml配置文件去创建实例的,那么我们就需要找到入口,从入口进去以后先不要急着看具体的实现细节,要先理清楚主方法里面大概做了哪些事,然后再去看各个方法是怎么做的

  4)多折腾、勤折腾

    研究完源码以后,知道源码能做什么、是怎么做的了,那么就可以写一些代码去测试他是不是确实能做到。或者知道源码有一些扩展点,就自己尝试去扩展一下

方法二:

  1)掌握研究的对象和研究对象的核心概念:搞明白框架都能做什么,是怎么做的。

    比如我们要研究Spring的源码,那么研究的对象就是Spring,Spring的核心概念有IOC、DI、AOP等,那么我们就需要搞明白这些核心概念能做什么,是怎么做的

  2)自己动手尝试去实现。 

  3)自己实现完以后,再去对比看源码里面是怎么实现的,源码里面为什么要那样去实现,有什么好处,学习源码里面好的地方

前面的两种方法,个人比较推荐方法一,因为每个人的水平不一样,方法一相对方法二来说要简单一点

前面已经介绍了两种学习源码的方法,那么怎么深入到源码里面去看别人是怎么做、选择性的去看某一部分源码是怎么做的呢?针对不同的情况,有下面的方法:

第一种方式:

  刚刚接触到一个新框架,完全不知道源码是干什么的,这种情况就得找到官方文档里面的使用示例找到入口,然后一步一步的去调试拿到整个调用栈,拿到整个调用栈以后就知道主干流程了,再去分析自己感兴趣的部分是怎么实现的就比较简单了(比较费时

第二种方式:

经过 学习源码的方法的方法一中的第 1)步 分析,知道源码里面要做某一件事,那就找到官方文档里面的使用示例找到入口,然后找到做某一件事的地方,打个断点,直接debug到做这件事地方拿到调用栈去分析,看都经过了哪些处理,然后去分析自己感兴趣的部分是怎么实现的。

比如IOC容器加载配置文件创建bean实例时一定会有注册bean定义的步骤,那么我们就先根据类的继承体系找到注册bean定义的类和对应的方法的实现的地方,在里面打个断点,直接debug到注册的方法的断点的地方时就能获取到调用栈了,然后再根据调用栈分析Spring要完成根据xml配置创建bean实例都有哪些类参与进来。

下面就来举例说明:

首先从官方文档可以得出如下使用示例:

官方文档:

使用示例:

ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");

然后进入ClassPathXmlApplicationContext里面

我们知道IOC容器的工作过程是加载xml、解析xml得到bean定义、把bean定义注册到bean工厂里面、bean工厂根据bean定义创建bean实例,那么我们就根据ClassPathXmlApplicationContext的继承体系先找到哪个类里面持有bean工厂,找到持有bean工厂的地方以后先看有没有注册bean定义相关的方法,根据继承体系寻找,最终发现在父类AbstractRefreshableApplicationContext里面持有Bean工厂DefaultListableBeanFactory:

    /** Bean factory for this context. */
@Nullable
private DefaultListableBeanFactory beanFactory;

通过在AbstractRefreshableApplicationContext里面查找,没有找到注册bean定义相关的方法,那么我们就看DefaultListableBeanFactory的里面有没有注册bean定义相关的方法,最终发现DefaultListableBeanFactory里面果然有注册bean定义的方法registerBeanDefinition

    @Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {

通过查看DefaultListableBeanFactory继承体系,我们可以看到DefaultListableBeanFactory实现了BeanDefinitionRegistry这个接口来实现bean定义注册

那么我们就在registerBeanDefinition(String beanName, BeanDefinition beanDefinition)方法里面打个断点,然后debug运行前面的示例代码到这里:

到这里我们就能拿到整个调用栈了:

拿到调用栈以后,我们就可以来分析Spring是怎么加载xml、解析xml获取bean定义、注册bean定义到bean工厂的了

那么怎么来具体分析调用栈呢?

主要看调用栈(看从开始到注册bean定义这件事情)用到了哪些类的哪些方法,看传参。工作是如何分配、分工协作完成的。
看传参重点是看输入的参数(如xml配置文件的路径)在这些类中是怎么变化的(代码的本质其实就是对输入数据的各种处理得到最终想要的结果),从而知道每一个类是干什么用的。分析完整个调用栈以后,想要了解哪一部分就点击对应的调用栈去分析就行了。

从调用栈可以看到要加载xml、解析xml获取bean定义、注册bean定义到bean工厂这些事需要三个类依次参与进来:

说明:

方法里面含有<init>的表示是在构造函数进行初始化,方法里面带有(AbstractApplicationContext).refresh()的表示调用的是AbstractApplicationContext父类的refresh()方法,其他的类似

1)ClassPathXmlApplicationContext:初始化、准备BeanFactory

2)XmlBeanDefinitionReader:输入的xml配置文件路径的字符串到Document的转换

3)DefaultBeanDefinitionDocumentReader 解析Document得到bean定义持有器BeanDefinitionholder

4) 后面的步骤就是把BeanDefinitionholder里面的Bean定义注册到Bean工厂里面

三、Eclipse里面查看源码的常用快捷键和方法

前提:在eclipse里面导入了源码或者用maven引入了源码的依赖

1. 查找源码的类的快捷键 

  Ctrl+Shift+T 然后输入要看的类

2. 查看一个类继承了哪些类的以及有哪些子类

 选中要查看的类,右键-选择Open Type Hierarchy(打开类的继承体系)

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory,HierarchicalBeanFactory,MessageSource,ApplicationEventPublisher, ResourcePatternResolver

 查看继承了哪些类:

查看有哪些子类:

选中部分里面对应的成员:

3. 查看一个类都有哪些子类

  选择要看的类 然后Ctrl+T

框架源码系列五:学习源码的方法(学习源码的目的、 学习源码的方法、Eclipse里面查看源码的常用快捷键和方法)的更多相关文章

  1. 框架源码系列十:Spring AOP(AOP的核心概念回顾、Spring中AOP的用法、Spring AOP 源码学习)

    一.AOP的核心概念回顾 https://docs.spring.io/spring/docs/5.1.3.RELEASE/spring-framework-reference/core.html#a ...

  2. Eclipse无法查看源码 提示source not found

    学习项目代码的时候想要看一下Cookie的源码,已经确定下载到了本地,可是Ctrl+左键点进去,提示source not found(如下图),百度了以后,大家普遍认为需要安装反编译插件jad. 看了 ...

  3. 33 Eclipse无法查看源码解决

    问题如图 点击 Attach Source 解决方法 下载src.zip包,src包地址:https://pan.baidu.com/s/1oAqqqHO 选择此src包即可

  4. eclipse如何查看源码

    方式一: Source not found The JAR file X:\xxxx\xxxx\xxxx\xx has no source attachment. 没有源附件. You can att ...

  5. eclipse中查看字节码

    1:在线安装ByteCode插件 打开Eclipse Go to"Help -> Install new Software... -> Work with:"中选择By ...

  6. 手牵手,从零学习Vue源码 系列一(前言-目录篇)

    系列文章: 手牵手,从零学习Vue源码 系列一(前言-目录篇) 手牵手,从零学习Vue源码 系列二(变化侦测篇) 手牵手,从零学习Vue源码 系列三(虚拟DOM篇) 陆续更新中... 预计八月中旬更新 ...

  7. Typescript | Vue3源码系列

    TypeScript 是开源的,TypeScript 是 JavaScript 的类型的超集,它可以编译成纯 JavaScript.编译出来的 JavaScript 可以运行在任何浏览器上.TypeS ...

  8. eclipse导出附带源码的jar包

    最近在搞Andengine游戏开发,发现andengine的jar包可以直接点击查看源码,而其他项目的jar包却看不了,因此自己研究了下如何生成可以直接查看源码的jar包. 1.eclipse中点击项 ...

  9. eclipse 查看源码 source not found

    是因为eclipse里面没有设置好源码路径. 源码路径在jdk安装包里面 C:/Program Files/Java/jdk1.8.0_191/src.zip  这个src.zip文件, 设置ecli ...

随机推荐

  1. java的类和对象

    创建狗狗类: /** * 狗狗类 * @author Administrator * */ public class Dog { String name="无名氏"; //姓名 i ...

  2. [COCI2013]DLAKAVAC

    [COCI2013]DLAKAVAC 题目大意: 有一个长度为\(m(m\le1500)\)的\(01\)串\(A\),进行\(k(k\le10^{18})\)次操作.一次操作完的串中若\(A_i=1 ...

  3. BZOJ4223 : Tourists

    将位置划分成$O(m)$段区间,每段最早被阻挡的时间可以用堆维护. 那么每段区间对询问的贡献独立,扫描线处理即可. 时间复杂度$O(m\log m)$. #include<cstdio> ...

  4. git上传本地项目到github,方法2

    第一步:去github上创建自己的Repository,创建页面如下图所示: 填写相应信息后点击create即可 Repository name: 仓库名称 Description(可选): 仓库描述 ...

  5. Java 构造器 通过私有构造器强化不可实例化的能力

    只有当类不包含显式的构造器时,编译器才会生成一个公有的.无参的缺省构造器.只要让一个类包含私有构造器,这个类就不能被实例化了.示例: // 工具类 public class UtilityClass ...

  6. react-native 报错 RawText "" must be wrapped in an explicit <Text> component

    刚才又遇到了一个坑,找了好久,问题如下: 开始以为是Text标签怎么有问题了,结果是下面的原因影响的: 上图第二行,标签和注释中间多了一个空格,就会报这个错误. 解决办法 1.将空格删掉 <Re ...

  7. Lua模块的加载与内存释放

    今天早上听说一件事情让我觉得很诡异的事情:公司线上的一款游戏,加载一份配置资源后,内存涨了几十M,然后内存再也下不来了.因为好奇,所以要来了最大的一个配置文件(4.5M,去除空格与换行后的大小),进行 ...

  8. MySQL表与表之间的SQL Joins图介绍

    下图很好的解释了各表之间SQL Joins之间的关系

  9. shell编程学习笔记(八):Shell中的if条件判断

    编程语言中都有条件判断,shell编程也不例外,下面我们来看一下shell中应该怎么使用if条件判断 以下蓝色字体部分为Linux命令,红色字体的内容为输出的内容: # cd /opt/scripts ...

  10. shell编程学习笔记(六):cat命令的使用

    这一篇不是讲shell编程的,专门讲cat命令.shell编程书用到了这个cat命令,顺便说一下cat命令. cat命令有多种用法,我一一来列举(以下蓝色字体部分为Linux命令,红色字体的内容为输出 ...