序言

读源码是绝大多数开发人员高阶的有效途径,前段时间了解到许多好友意见反馈读了许多源码但是斩获并非很大,看了许多源码总是Monpazier,有许多疑惑。

主要就表现为:

读源码的时候无人知晓该读啥很容易沉沦在技术细节中,增容时秋千跳晕了,极难延续下去念完迅速就忘记了,无法充分运用

网路上也会有许多讲某一具体开源码的系列产品该文,通常比较乏味,传授给的都是鱼而并非渔。 虽说:授人以鱼比不上少击众。

我坚信绝大多数老师希望得到认识论等级、更加体系化介绍怎样更快地写作源码的该文。 有鉴于此,在这里我急于将自己的读源码实战经验教给大家,坚信会让许多人认知问题的症结,得出许多出乎意料的新颖提议,让倍受读源码疑惑的老师能够找到方向。

该文重点讲到如下表所示内容:

为甚么许多人读源码斩获并不大?读源码到底读甚么?有甚么样读源码重要的价值观?有甚么样好的读源码突破口?有甚么样读源码非常新颖的基本功?

总体概要:

自动草稿

为甚么许多人读源码斩获并不大?

事实证明,绝大多数人读源码斩获并不大的主要就原因如下表所示:

缺少总体观念,沉沦在技术细节中(如增容源码时秋千,最后跳晕了)缺少思索(学而不思则罔,思而不学则殆!)不知道读源码到底读甚么(如源码的设计价值观)视角单个(如从补救视角、操控性强化视角、程序语言视角、每天递交、程序代码、注解等)方法单个(如要学的高阶的增容基本功,要学的排程图应用程序)缺少输入(不会输入成该文,不能Jaunpur别人听)

读源码到底读甚么?

做事要以终为始,只有搞清楚读源码我们到底想得到甚么,我们才能避免走马观花 最终将斩获无多的尴尬场景。

那么读源码读的是甚么?我们要关注甚么样方面呢?

读目的:该框架是为了解决甚么问题?比同类框架相比的优劣是甚么?这对认知框架非常重要。

读注解:许多人读源码会忽略注解。提议大家读源码时一定要重视注解。因为优秀的开源项目,通常某一类、某一函数的目的、核心逻辑、核心参数的解释,异常的发生场景等都会写到注解中,这对我们学习源码,分析问题有极大的帮助。

读逻辑:这里所谓的逻辑是指语句或者子函数的顺序问题。我们要重视作者编码的顺序,了解为甚么先写 A 再写 B,背后的原因是甚么。

读价值观:所谓价值观是指源码背后体现出了甚么样设计原则,比如是并非和程序语言的六大原则相符?是并非符合高内聚低耦合?是并非体现某种操控性强化价值观?

读原理:读核心实现步骤,而并非记忆每行代码。核心原理和步骤最重要。

读编码风格:一般来说优秀的源码的代码风格都比较优雅。我们可以通过源码来学习编码规范。

读编程基本功:作者是否采用了某种程序语言,某种编程基本功实现了出乎意料的效果。

读设计方案:读源码不仅包含具体的代码,更重要的是设计方案。比如我们下载一个秒杀系统 / 商城系统的代码,我们可以学习密码加密的方案,学习分布式事务处理的方案,学习幂等的设计方案,超卖问题的解决方案等。因为掌握这些方案之后对提升我们自己的工作实战经验非常有帮助,我们工作中做技术方案时可以参考这些优秀项目的方案。

读源码的误区

许多人读源码不顺利,效果不好,通常都会有些共性。

那么读源码通常会有甚么样误区呢?

开局打 Boss

经常打游戏的好友都知道,开局直接打 Boss 无异于送人头。

一般开局先打野,练就了实战经验再去挑战 Boss。

如果开始尝试学习源码就直接拿大型开源框架入手容易自信心受挫,导致放弃。

佛系青年

经常打游戏的好友也都知道,打游戏要讲究策略,随便瞎打很容易失败。

有些好友决定读源码,但又缺少规划,随心所欲,往往效果不太好。

对着答案做题

我们知道许多小学生、初高中生,甚至许多大学生学习会出现眼高手低的情况。

有些人做题时并并非先思索,而是先看答案,然后对着答案的思路来认知题目。在这种模式下,绝大多数题目都理所当然地这么做,会误认为自己真正懂了。但是即使是原题,也会做错,想不出思路。

同样地,许多人读源码也会走到这个误区中。直接看源码的解析,直接看源码的写法,缺少关键的前置步骤,即先自己思索再对照源码。

读源码的价值观

先会用再读源码

学习某一源码之前一定要对源码的基本用法有一个初步了解。

如果对框架没有基本的了解就直接读源码,效果通常不会太好。

一般优秀的开源项目,都会得出许多简单的官方示例代码,大家可以将官方示例代码跑起来,了解基本用法。

大家也可以去 GitHub 上搜索并拉取某一技术的 Demo,某一技术的 hello world 项目,快速用起来。

如 Dubbo 官方文档就得出了快速上手示例代码 ;轻量级的分布式服务框架 jupiter README.md 就得出了简单的调用示例。许多开源项目得出了多个框架的示例代码,如 tutorials。

先易后难

循序渐进是学习的一大规律。

一方面,可以先尝试写作较为简单的开源项目源码,比如 commons-lang、commons-collection、guava、mapstruct 等工具性质的源码。

另外还可以尝试寻找某一框架的简单版,先从简单版学起,看透了再学大型的开源项目就容易许多。

可能许多人会说不好找,其实绝大多数知名开源的项目都会有简单版,用心找绝大多数都可以找到, 比如 Spring 的简易版、Dubbo 简易版。

先总体后局部

先总体后局部是非常重要的一个认知规则,体现了总体观念。

如果对框架缺少总体认识,很容易陷入局部技术细节之中。

先总体后局部包括多种含义,下面会介绍几种核心的含义。

先看架构再读源码

大家可以通过框架的官方文档了解其总体架构,了解其核心原理,然后再去看具体的源码。

但是许多人总会忽视这个步骤。

如轻量级分布式服务框架 jupiter 框架 的 README.md 得出了框架的总体架构:

自动草稿

(图片来自:jupiter 项目 README.md 文档)

对框架有了一个总体了解之后,再去看具体的实现就会容易许多。

先看项目结构再读源码

先总体后局部,还包括先看项目的分包,再具体看源码

自动草稿

(图片来自:jupiter 项目结构)

通过项目的报名,如 monitor、registry、serialization、example、common 等就可以明白该包下的代码意图。

先看类的函数列表再读源码

通过 IDEA 的函数列表功能,可以快速了解某一类包含的函数,可以对这个类的核心功能有一个初步的认识。

这种方式在读某些源码时效果非常棒。

更重要的是,如果能够养成查看函数列表的习惯,可以发现许多重要但是被忽略的函数,在未来的项目开发中很可能会用到。

下图为 commons-lang3 的 3.9 版本中 StringUtils 类的函数列表示意图:

自动草稿

先看总体逻辑再看某一步骤

比如一个大函数可能分为多个步骤,我们先要认知某一步骤的意图,了解为甚么先执行子函数 1, 再执行子函数 2 等。

然后再去观察某一子函数的技术细节。

以 spring-context 的 5.1.0.RELEASE 版本的 IOC 容器的核心org.springframework.context.support.AbstractApplicationContext 的核心函数 refresh 为例:

@Overridepublicvoidrefresh()throwsBeansException, IllegalStateException{synchronized(this.startupShutdownMonitor) {// Prepare this context for refreshing.// 1 初始化前的预处理prepareRefresh();// Tell the subclass to refresh the internal bean factory.// 2 告诉子类去 refresh 内部的 bean FactoryConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.// 3 BeanFactory 的预处理配置prepareBeanFactory(beanFactory);try{// Allows post-processing of the bean factory in context subclasses.// 4 准备 BeanFactory 完成后进行后置处理postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.// 5 执行 BeanFactory 创建后的后置处理器invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.// 6 注册 Bean 的后置处理器registerBeanPostProcessors(beanFactory);// Initialize message source for this context.// 7 初始化 MessageSourceinitMessageSource();// Initialize event multicaster for this context.// 8 初始化事件派发器initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.// 9 子类的多态 onRefreshonRefresh();// Check for listener beans and register them.// 10 检查监听器并注册registerListeners();// Instantiate all remaining (non-lazy-init) singletons.// 11 实例化所有剩下的单例 Bean (非懒初始化)finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.// 12 最后一步,完成容器的创建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.// 销毁已经常见的单例 beandestroyBeans();// Reset active flag.// 重置 active 标志cancelRefresh(ex);// Propagate exception to caller.// 将异常丢给调用者throwex;
}finally{// Reset common introspection caches in Springs core, since we// might not ever need metadata for singleton beans anymore…// 重置缓存resetCommonCaches();
}
}
}

我们可以要特别重视每个步骤的含义,思索为甚么这些要这么设计,然后再进入某一子函数中去了解具体的实现。

比如再去了解第 7 步的具体编码实现。

/**
* Initialize the MessageSource.
* Use parents if none defined in this context.
*/
protectedvoid initMessageSource() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();if(beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);// Make MessageSource aware of parent MessageSource.if(this.parent !=null

1.本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2.分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3.不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4.本站提供的源码、模板、插件等其他资源,都不包含技术服务请大家谅解!
5.如有链接无法下载或失效,请联系管理员处理!
6.本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!